agentix-cli 0.2.0 → 0.4.0

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 (39) hide show
  1. package/README.md +192 -107
  2. package/dist/agent-K2YOEOJ5.js +2 -0
  3. package/dist/chunk-4YCH6IZV.js +2 -0
  4. package/dist/chunk-AIBBZF4E.js +41 -0
  5. package/dist/chunk-AIBBZF4E.js.map +1 -0
  6. package/dist/chunk-F73GPYCO.js +106 -0
  7. package/dist/chunk-F73GPYCO.js.map +1 -0
  8. package/dist/chunk-M7HKBG3V.js +2 -0
  9. package/dist/chunk-M7HKBG3V.js.map +1 -0
  10. package/dist/chunk-MGMZNJCE.js +46 -0
  11. package/dist/chunk-MGMZNJCE.js.map +1 -0
  12. package/dist/{chunk-6PVFYFUE.js → chunk-X7UN6JAA.js} +2 -2
  13. package/dist/{chunk-6PVFYFUE.js.map → chunk-X7UN6JAA.js.map} +1 -1
  14. package/dist/chunk-Z4GC5D6D.js +12 -0
  15. package/dist/chunk-Z4GC5D6D.js.map +1 -0
  16. package/dist/cli.js +9 -155
  17. package/dist/cli.js.map +1 -1
  18. package/dist/heal-UV5A6B5T.js +2 -0
  19. package/dist/index.d.ts +265 -11
  20. package/dist/index.js +85 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/loader-6VSM6FSY.js +2 -0
  23. package/dist/providers-AVYG63KK.js +2 -0
  24. package/dist/providers-AVYG63KK.js.map +1 -0
  25. package/package.json +3 -1
  26. package/dist/agent-AI6DUEPU.js +0 -2
  27. package/dist/chunk-FUYKPFUV.js +0 -46
  28. package/dist/chunk-FUYKPFUV.js.map +0 -1
  29. package/dist/chunk-NZ6W33BD.js +0 -116
  30. package/dist/chunk-NZ6W33BD.js.map +0 -1
  31. package/dist/chunk-THMHQELC.js +0 -106
  32. package/dist/chunk-THMHQELC.js.map +0 -1
  33. package/dist/heal-MJLBETRV.js +0 -2
  34. package/dist/loader-PHU6STSZ.js +0 -2
  35. package/dist/providers-MPYTYJVB.js +0 -2
  36. /package/dist/{agent-AI6DUEPU.js.map → agent-K2YOEOJ5.js.map} +0 -0
  37. /package/dist/{heal-MJLBETRV.js.map → chunk-4YCH6IZV.js.map} +0 -0
  38. /package/dist/{loader-PHU6STSZ.js.map → heal-UV5A6B5T.js.map} +0 -0
  39. /package/dist/{providers-MPYTYJVB.js.map → loader-6VSM6FSY.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/a2a/client.ts","../src/a2a/mesh.ts","../src/daemon/config.ts","../src/agents/runtime.ts","../src/wiki/store.ts","../src/agents/sessions.ts","../src/agents/registry.ts","../src/channels/router.ts","../src/channels/telegram-format.ts","../src/channels/telegram.ts","../src/channels/whatsapp.ts","../src/crons/scheduler.ts","../src/daemon/index.ts","../src/channels/discord.ts","../src/utils/get-package-info.ts"],"sourcesContent":["import type { AgentCard, Task, MessagePart, JsonRpcResponse } from \"./types\"\n\n// --- A2A Client: call remote agents via A2A protocol ---\n\nexport class A2AClient {\n private baseUrl: string\n private token?: string\n\n constructor(baseUrl: string, token?: string) {\n this.baseUrl = baseUrl.replace(/\\/$/, \"\")\n this.token = token\n }\n\n /**\n * Fetch the remote agent's card.\n */\n async getAgentCard(): Promise<AgentCard> {\n const res = await fetch(`${this.baseUrl}/.well-known/agent-card.json`, {\n headers: this.headers(),\n })\n if (!res.ok) throw new Error(`Failed to fetch agent card: ${res.status}`)\n return res.json() as Promise<AgentCard>\n }\n\n /**\n * Send a task synchronously and wait for completion.\n */\n async sendTask(\n text: string,\n metadata?: Record<string, unknown>,\n ): Promise<Task> {\n const response = await this.rpc(\"tasks/send\", {\n id: `task-${Date.now().toString(36)}`,\n message: {\n role: \"user\",\n parts: [{ type: \"text\", text }] as MessagePart[],\n },\n metadata,\n })\n\n if (response.error) {\n throw new Error(`A2A error: ${response.error.message}`)\n }\n\n return response.result as Task\n }\n\n /**\n * Send a task with SSE streaming.\n */\n async *sendTaskStream(\n text: string,\n metadata?: Record<string, unknown>,\n ): AsyncIterable<{ state: string; message?: string; final: boolean }> {\n const body = JSON.stringify({\n jsonrpc: \"2.0\",\n id: 1,\n method: \"tasks/sendSubscribe\",\n params: {\n id: `task-${Date.now().toString(36)}`,\n message: {\n role: \"user\",\n parts: [{ type: \"text\", text }],\n },\n metadata,\n },\n })\n\n const res = await fetch(this.baseUrl, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n \"Content-Type\": \"application/json\",\n \"Accept\": \"text/event-stream\",\n },\n body,\n })\n\n if (!res.ok || !res.body) {\n throw new Error(`A2A stream error: ${res.status}`)\n }\n\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buffer = \"\"\n\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n buffer += decoder.decode(value, { stream: true })\n const lines = buffer.split(\"\\n\")\n buffer = lines.pop() || \"\"\n\n for (const line of lines) {\n if (line.startsWith(\"data: \")) {\n try {\n const data = JSON.parse(line.slice(6))\n yield {\n state: data.state,\n message: data.message?.parts?.[0]?.text,\n final: data.final,\n }\n } catch {\n // Skip malformed events\n }\n }\n }\n }\n }\n\n /**\n * Get task status by ID.\n */\n async getTask(taskId: string): Promise<Task> {\n const response = await this.rpc(\"tasks/get\", { id: taskId })\n if (response.error) {\n throw new Error(`A2A error: ${response.error.message}`)\n }\n return response.result as Task\n }\n\n /**\n * Cancel a running task.\n */\n async cancelTask(taskId: string): Promise<Task> {\n const response = await this.rpc(\"tasks/cancel\", { id: taskId })\n if (response.error) {\n throw new Error(`A2A error: ${response.error.message}`)\n }\n return response.result as Task\n }\n\n private async rpc(method: string, params: Record<string, unknown>): Promise<JsonRpcResponse> {\n const res = await fetch(this.baseUrl, {\n method: \"POST\",\n headers: {\n ...this.headers(),\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n jsonrpc: \"2.0\",\n id: Date.now(),\n method,\n params,\n }),\n })\n\n if (!res.ok) {\n throw new Error(`A2A HTTP error: ${res.status}`)\n }\n\n return res.json() as Promise<JsonRpcResponse>\n }\n\n private headers(): Record<string, string> {\n const h: Record<string, string> = {}\n if (this.token) {\n h[\"Authorization\"] = `Bearer ${this.token}`\n }\n return h\n }\n}\n","import type { MeshPeer, DaemonConfig } from \"@/daemon/config\"\nimport type { AgentCard, AgentSkill } from \"./types\"\nimport { A2AClient } from \"./client\"\n\n// --- A2A Mesh: peer discovery, health checks, agent directory ---\n\nexport interface PeerState {\n peer: MeshPeer\n client: A2AClient\n healthy: boolean\n lastCheck?: Date\n agentCard?: AgentCard\n agents: AgentSkill[]\n}\n\nexport class A2AMesh {\n private peers: Map<string, PeerState> = new Map()\n private healthTimer?: ReturnType<typeof setInterval>\n private config: DaemonConfig\n private log: (...args: unknown[]) => void\n\n constructor(\n config: DaemonConfig,\n log: (...args: unknown[]) => void = console.error.bind(console, \"[mesh]\"),\n ) {\n this.config = config\n this.log = log\n\n for (const peer of config.mesh.peers) {\n this.peers.set(peer.name, {\n peer,\n client: new A2AClient(peer.url, peer.token),\n healthy: false,\n agents: [],\n })\n }\n }\n\n /**\n * Start the mesh: discover peers and begin health checks.\n */\n async start(): Promise<void> {\n this.log(`Mesh starting with ${this.peers.size} peer(s)`)\n\n // Initial discovery\n await this.discoverAll()\n\n // Periodic health checks\n const interval = this.config.mesh.healthCheck.interval * 1000\n this.healthTimer = setInterval(() => this.discoverAll(), interval)\n }\n\n async stop(): Promise<void> {\n if (this.healthTimer) {\n clearInterval(this.healthTimer)\n }\n }\n\n /**\n * Discover agent cards from all peers.\n */\n async discoverAll(): Promise<void> {\n const results = await Promise.allSettled(\n Array.from(this.peers.entries()).map(([name, state]) =>\n this.discoverPeer(name, state),\n ),\n )\n\n const healthy = Array.from(this.peers.values()).filter((p) => p.healthy).length\n this.log(`Discovery complete: ${healthy}/${this.peers.size} peers healthy`)\n }\n\n private async discoverPeer(name: string, state: PeerState): Promise<void> {\n const timeout = this.config.mesh.healthCheck.timeout * 1000\n\n try {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeout)\n\n const card = await state.client.getAgentCard()\n clearTimeout(timer)\n\n state.healthy = true\n state.lastCheck = new Date()\n state.agentCard = card\n state.agents = card.skills || []\n\n this.log(`Peer \"${name}\" healthy: ${card.name} (${state.agents.length} skills)`)\n } catch (e: any) {\n state.healthy = false\n state.lastCheck = new Date()\n this.log(`Peer \"${name}\" unreachable: ${e.message}`)\n }\n }\n\n /**\n * Send a task to a remote peer by name.\n * Uses the peer's /task HTTP endpoint (agentx daemon API).\n * If no agent specified, uses the first available agent on the peer.\n */\n async sendTask(peerName: string, text: string, agentId?: string): Promise<string> {\n const state = this.peers.get(peerName)\n if (!state) throw new Error(`Unknown peer: ${peerName}`)\n if (!state.healthy) throw new Error(`Peer \"${peerName}\" is not healthy`)\n\n // Default to first agent on the peer\n const agent = agentId || state.agents[0]?.id\n if (!agent) throw new Error(`Peer \"${peerName}\" has no agents`)\n\n const url = `${state.peer.url}/task`\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\" }\n if (state.peer.token) {\n headers[\"Authorization\"] = `Bearer ${state.peer.token}`\n }\n\n const res = await fetch(url, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ agent, message: text }),\n })\n\n if (!res.ok) {\n throw new Error(`Peer \"${peerName}\" /task error: ${res.status}`)\n }\n\n const data = await res.json() as { content?: string; error?: string }\n if (data.error) throw new Error(`Peer \"${peerName}\" agent error: ${data.error}`)\n return data.content || \"No response\"\n }\n\n /**\n * Find a peer that has a specific skill.\n */\n findPeerWithSkill(skillId: string): PeerState | undefined {\n for (const state of this.peers.values()) {\n if (state.healthy && state.agents.some((a) => a.id === skillId)) {\n return state\n }\n }\n return undefined\n }\n\n /**\n * Get the combined agent directory across all healthy peers.\n */\n directory(): Array<{\n peer: string\n peerUrl: string\n healthy: boolean\n skills: AgentSkill[]\n lastCheck?: Date\n }> {\n return Array.from(this.peers.entries()).map(([name, state]) => ({\n peer: name,\n peerUrl: state.peer.url,\n healthy: state.healthy,\n skills: state.agents,\n lastCheck: state.lastCheck,\n }))\n }\n}\n","import { z } from \"zod\"\nimport { readFileSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\n\n/**\n * Load .env file into process.env (simple, no dependency).\n */\nfunction loadDotEnv(dir: string): void {\n const envPath = resolve(dir, \".env\")\n if (!existsSync(envPath)) return\n\n const content = readFileSync(envPath, \"utf-8\")\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(\"#\")) continue\n const eqIdx = trimmed.indexOf(\"=\")\n if (eqIdx === -1) continue\n const key = trimmed.slice(0, eqIdx).trim()\n const value = trimmed.slice(eqIdx + 1).trim()\n if (!process.env[key]) {\n process.env[key] = value\n }\n }\n}\n\n// --- Daemon configuration schema & loader ---\n\nconst providerConfigSchema = z.object({\n apiKey: z.string().optional(),\n defaultModel: z.string().optional(),\n baseUrl: z.string().optional(),\n})\n\nconst agentConfigSchema = z.object({\n name: z.string(),\n workspace: z.string(),\n tier: z.enum([\"claude-code\", \"sdk\", \"orchestrator\"]).default(\"claude-code\"),\n provider: z.string().optional(),\n model: z.string().optional(),\n systemPrompt: z.string().optional(),\n mentions: z.array(z.string()).default([]),\n maxConcurrent: z.number().default(1),\n permissionMode: z.string().default(\"default\"),\n})\n\nconst telegramAccountSchema = z.object({\n token: z.string(),\n agentBinding: z.string(),\n})\n\nconst channelsConfigSchema = z.object({\n telegram: z.object({\n enabled: z.boolean().default(false),\n accounts: z.record(z.string(), telegramAccountSchema).default({}),\n policy: z.object({\n dm: z.enum([\"pair\", \"block\"]).default(\"pair\"),\n group: z.enum([\"mention-required\", \"all\"]).default(\"mention-required\"),\n }).default({}),\n }).default({}),\n whatsapp: z.object({\n enabled: z.boolean().default(false),\n sessionDir: z.string().default(\".agentx/whatsapp-sessions\"),\n defaultAgent: z.string().optional(),\n allowFrom: z.array(z.string()).optional(),\n routes: z.array(z.object({\n contact: z.string().optional(),\n group: z.string().optional(),\n agent: z.string(),\n })).default([]),\n }).default({}),\n discord: z.object({\n enabled: z.boolean().default(false),\n token: z.string().optional(),\n agentBinding: z.string().optional(),\n }).default({}),\n})\n\nconst cronJobSchema = z.object({\n enabled: z.boolean().default(true),\n schedule: z.string(),\n timezone: z.string().default(\"UTC\"),\n agent: z.string(),\n prompt: z.string(),\n timeout: z.number().default(600),\n model: z.string().optional(),\n onError: z.enum([\"log\", \"notify\", \"disable\"]).default(\"log\"),\n})\n\nconst meshPeerSchema = z.object({\n url: z.string(),\n name: z.string(),\n token: z.string().optional(),\n})\n\nconst meshConfigSchema = z.object({\n enabled: z.boolean().default(false),\n peers: z.array(meshPeerSchema).default([]),\n discovery: z.enum([\"static\", \"mdns\"]).default(\"static\"),\n healthCheck: z.object({\n interval: z.number().default(60),\n timeout: z.number().default(10),\n }).default({}),\n})\n\nexport const daemonConfigSchema = z.object({\n node: z.object({\n id: z.string(),\n name: z.string(),\n bind: z.string().default(\"127.0.0.1:18800\"),\n }),\n providers: z.record(z.string(), providerConfigSchema).default({}),\n agents: z.record(z.string(), agentConfigSchema).default({}),\n channels: channelsConfigSchema.default({}),\n crons: z.record(z.string(), cronJobSchema).default({}),\n mesh: meshConfigSchema.default({}),\n})\n\nexport type DaemonConfig = z.infer<typeof daemonConfigSchema>\nexport type AgentDef = z.infer<typeof agentConfigSchema>\nexport type CronJobDef = z.infer<typeof cronJobSchema>\nexport type MeshPeer = z.infer<typeof meshPeerSchema>\n\n/**\n * Expand environment variables in strings: ${VAR_NAME} -> process.env.VAR_NAME\n */\nfunction expandEnvVars(obj: unknown): unknown {\n if (typeof obj === \"string\") {\n return obj.replace(/\\$\\{(\\w+)\\}/g, (_match, name) => process.env[name] || \"\")\n }\n if (Array.isArray(obj)) {\n return obj.map(expandEnvVars)\n }\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[key] = expandEnvVars(value)\n }\n return result\n }\n return obj\n}\n\n/**\n * Load daemon config from agentx.json, with env var expansion and validation.\n */\nexport function loadDaemonConfig(configPath?: string): DaemonConfig {\n const paths = configPath\n ? [configPath]\n : [\n resolve(process.cwd(), \"agentx.json\"),\n resolve(process.cwd(), \".agentx/config.json\"),\n ]\n\n // Load .env from same directory as config search\n loadDotEnv(process.cwd())\n\n let raw: string | undefined\n let foundPath: string | undefined\n\n for (const p of paths) {\n if (existsSync(p)) {\n raw = readFileSync(p, \"utf-8\")\n foundPath = p\n break\n }\n }\n\n if (!raw || !foundPath) {\n throw new Error(\n `No config found. Create agentx.json or .agentx/config.json\\n` +\n `Searched: ${paths.join(\", \")}`\n )\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (e: any) {\n throw new Error(`Invalid JSON in ${foundPath}: ${e.message}`)\n }\n\n // Expand environment variables\n const expanded = expandEnvVars(parsed)\n\n // Validate\n const result = daemonConfigSchema.safeParse(expanded)\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\")\n throw new Error(`Config validation failed (${foundPath}):\\n${issues}`)\n }\n\n return result.data\n}\n\n/**\n * Validate agent workspace directories exist and have .claude/ setup.\n */\nexport function validateWorkspaces(config: DaemonConfig): string[] {\n const warnings: string[] = []\n\n for (const [id, agent] of Object.entries(config.agents)) {\n if (!existsSync(agent.workspace)) {\n warnings.push(`Agent \"${id}\": workspace not found at ${agent.workspace}`)\n continue\n }\n\n if (agent.tier === \"claude-code\") {\n const claudeDir = resolve(agent.workspace, \".claude\")\n if (!existsSync(claudeDir)) {\n warnings.push(\n `Agent \"${id}\": no .claude/ directory in workspace ${agent.workspace}. ` +\n `Claude Code native features (hooks, MCP, skills) won't be available.`\n )\n }\n }\n\n // Check provider availability\n const providerName = agent.provider || \"claude\"\n const providerConfig = config.providers[providerName]\n if (agent.tier !== \"claude-code\" && (!providerConfig || !providerConfig.apiKey)) {\n warnings.push(\n `Agent \"${id}\": provider \"${providerName}\" has no API key configured. ` +\n `Set providers.${providerName}.apiKey in config or use tier \"claude-code\" for subscription.`\n )\n }\n }\n\n // Validate cron agent bindings\n for (const [id, cron] of Object.entries(config.crons)) {\n if (!config.agents[cron.agent]) {\n warnings.push(`Cron \"${id}\": references unknown agent \"${cron.agent}\"`)\n }\n }\n\n // Validate channel agent bindings\n if (config.channels.telegram.enabled) {\n for (const [name, account] of Object.entries(config.channels.telegram.accounts)) {\n if (!config.agents[account.agentBinding]) {\n warnings.push(\n `Telegram account \"${name}\": references unknown agent \"${account.agentBinding}\"`\n )\n }\n }\n }\n\n return warnings\n}\n","import { execa } from \"execa\"\nimport { execFile, spawn } from \"child_process\"\nimport type { AgentDef } from \"@/daemon/config\"\n\n// --- Agent execution runtime ---\n// Routes agent tasks to the correct execution tier:\n// - claude-code: spawns claude CLI (subscription, full features)\n// - sdk: uses Claude Agent SDK (API key, programmatic)\n// - orchestrator: uses agentx's own agentic loop (any provider)\n\nexport interface AgentPeer {\n id: string\n name: string\n handle?: string // e.g. \"@noqta_devops_bot\"\n role?: string // from systemPrompt, first line\n}\n\nexport interface AgentTask {\n message: string\n agentId: string\n context?: {\n channel?: string\n sender?: string\n group?: string\n /** Attached media file (image, audio, video, document) */\n mediaPath?: string\n mediaType?: string\n /** Text of the message being replied to */\n replyToText?: string\n conversationHistory?: Array<{ role: string; content: string }>\n /** This agent's own handle on the current channel */\n myHandle?: string\n /** Other available agents and their handles */\n peers?: AgentPeer[]\n }\n}\n\nexport interface AgentResponse {\n content: string\n error?: string\n tokensUsed?: number\n duration?: number\n claudeSessionId?: string // Captured from Claude Code for session resumption\n}\n\n/** Callback for streaming text deltas */\nexport type StreamCallback = (delta: string, fullText: string) => void\n\n/**\n * Build the prompt from agent config + task context + conversation history.\n */\nfunction buildPrompt(agent: AgentDef, task: AgentTask, historyContext?: string): string {\n const parts: string[] = []\n\n if (agent.systemPrompt) {\n parts.push(agent.systemPrompt)\n }\n\n // Inject environment context so the agent knows where it is and who else is available\n if (task.context) {\n const ctx = task.context\n const envLines: string[] = [\"\", \"[Environment]\"]\n\n if (ctx.channel) envLines.push(`Channel: ${ctx.channel}`)\n if (ctx.group) envLines.push(`Group: ${ctx.group}`)\n if (ctx.sender) envLines.push(`Message from: ${ctx.sender}`)\n if (ctx.myHandle) envLines.push(`Your handle on this channel: ${ctx.myHandle}`)\n\n if (ctx.peers?.length) {\n envLines.push(\"\")\n envLines.push(\"[Team — other agents you can mention to delegate or collaborate]\")\n for (const peer of ctx.peers) {\n const handle = peer.handle ? ` (mention: ${peer.handle})` : \"\"\n const role = peer.role ? ` — ${peer.role}` : \"\"\n envLines.push(`• ${peer.name}${handle}${role}`)\n }\n envLines.push(\"\")\n envLines.push(\"To involve another agent, mention their handle in your response and they will automatically see it and reply.\")\n }\n\n parts.push(envLines.join(\"\\n\"))\n }\n\n // Reply-to context (when user replies to a specific message)\n if (task.context?.replyToText) {\n parts.push(\"\")\n parts.push(`[Replying to]: ${task.context.replyToText}`)\n }\n\n // Attached media\n if (task.context?.mediaPath) {\n parts.push(\"\")\n parts.push(`[Attached file: ${task.context.mediaPath}]`)\n parts.push(`[File type: ${task.context.mediaType || \"unknown\"}]`)\n if (task.context.mediaType?.startsWith(\"image/\")) {\n parts.push(\"Please read/view this image file and describe or respond to it.\")\n } else if (task.context.mediaType?.startsWith(\"audio/\")) {\n parts.push(\"Please transcribe this audio file and respond to its content.\")\n } else if (task.context.mediaType?.startsWith(\"video/\")) {\n parts.push(\"A video file is attached. Describe what you can determine about it.\")\n } else {\n parts.push(\"Please read this file and respond based on its content.\")\n }\n }\n\n // Inject conversation history for session continuity\n if (historyContext) {\n parts.push(\"\")\n parts.push(historyContext)\n }\n\n parts.push(\"\")\n parts.push(task.message)\n\n return parts.join(\"\\n\")\n}\n\n/**\n * Build CLI args for claude command.\n */\nfunction buildClaudeArgs(\n agent: AgentDef,\n prompt: string,\n streaming: boolean,\n resumeSessionId?: string,\n): string[] {\n const args: string[] = [\n \"-p\", prompt,\n \"--output-format\", streaming ? \"stream-json\" : \"json\",\n ]\n\n // stream-json requires --verbose in recent Claude Code versions\n if (streaming) {\n args.push(\"--verbose\")\n }\n\n // Resume existing Claude session for conversation continuity\n if (resumeSessionId) {\n args.push(\"--resume\", resumeSessionId)\n }\n\n if (agent.model) {\n args.push(\"--model\", agent.model)\n }\n\n if (agent.permissionMode === \"bypassPermissions\") {\n args.push(\"--dangerously-skip-permissions\")\n }\n\n return args\n}\n\n/**\n * Parse JSON output from `claude -p --output-format json`.\n * Returns the text result and session_id.\n */\nfunction parseClaudeJsonOutput(stdout: string): { text: string; sessionId?: string } {\n try {\n const data = JSON.parse(stdout)\n return {\n text: data.result || data.content || \"\",\n sessionId: data.session_id,\n }\n } catch {\n // Not JSON — return raw text (fallback for non-json output)\n return { text: stdout }\n }\n}\n\n/**\n * Execute a task using the Claude Code CLI (tier: \"claude-code\").\n * Non-streaming — waits for full response.\n */\nexport async function executeClaudeCode(\n agent: AgentDef,\n task: AgentTask,\n historyContext?: string,\n resumeSessionId?: string,\n): Promise<AgentResponse> {\n const start = Date.now()\n const prompt = buildPrompt(agent, task, resumeSessionId ? undefined : historyContext)\n const args = buildClaudeArgs(agent, prompt, false, resumeSessionId)\n\n try {\n const { stdout, stderr, exitCode } = await new Promise<{ stdout: string; stderr: string; exitCode: number }>((resolve, reject) => {\n const proc = execFile(\"claude\", args, {\n cwd: agent.workspace,\n timeout: 600_000,\n maxBuffer: 10 * 1024 * 1024,\n env: { ...process.env, HOME: process.env.HOME || \"/home/\" + (process.env.USER || \"clawd\") },\n }, (error, stdout, stderr) => {\n // Always resolve — we handle errors ourselves based on stdout/stderr\n resolve({\n stdout: stdout || \"\",\n stderr: stderr || \"\",\n exitCode: error ? (error as any).code ?? 1 : 0,\n })\n })\n })\n\n if (!stdout && exitCode !== 0) {\n const errMsg = stderr?.trim() || `Claude Code exited with code ${exitCode}`\n return {\n content: \"\",\n error: errMsg.slice(0, 300),\n duration: Date.now() - start,\n }\n }\n\n // Parse JSON output — gives us both text and session_id cleanly\n const parsed = parseClaudeJsonOutput(stdout)\n\n return {\n content: parsed.text,\n duration: Date.now() - start,\n claudeSessionId: parsed.sessionId,\n }\n } catch (error: any) {\n console.error(`[runtime] execFile threw: ${error.message}`)\n return {\n content: \"\",\n error: error.message || \"Claude Code failed\",\n duration: Date.now() - start,\n }\n }\n}\n\n/**\n * Execute with streaming — calls onDelta with text chunks as they arrive.\n * Uses claude --output-format stream-json to get real-time output.\n */\nexport async function executeClaudeCodeStreaming(\n agent: AgentDef,\n task: AgentTask,\n onDelta: StreamCallback,\n historyContext?: string,\n resumeSessionId?: string,\n): Promise<AgentResponse> {\n const start = Date.now()\n const prompt = buildPrompt(agent, task, resumeSessionId ? undefined : historyContext)\n const args = buildClaudeArgs(agent, prompt, true, resumeSessionId)\n\n let fullText = \"\"\n\n try {\n const proc = execa(\"claude\", args, {\n cwd: agent.workspace,\n timeout: 600_000, // 10 minutes\n reject: false,\n env: process.env,\n // Don't buffer — we'll read stdout line by line\n buffer: false,\n })\n\n // Parse stream-json output line by line\n if (proc.stdout) {\n let lineBuffer = \"\"\n\n proc.stdout.on(\"data\", (chunk: Buffer) => {\n lineBuffer += chunk.toString()\n const lines = lineBuffer.split(\"\\n\")\n lineBuffer = lines.pop() || \"\"\n\n for (const line of lines) {\n if (!line.trim()) continue\n try {\n const event = JSON.parse(line)\n\n // Claude stream-json emits different event types\n // \"assistant\" messages with content contain the text\n if (event.type === \"assistant\" && event.message?.content) {\n for (const block of event.message.content) {\n if (block.type === \"text\" && block.text) {\n const delta = block.text.slice(fullText.length)\n if (delta) {\n fullText = block.text\n onDelta(delta, fullText)\n }\n }\n }\n }\n\n // \"content_block_delta\" for streaming text\n if (event.type === \"content_block_delta\" && event.delta?.text) {\n fullText += event.delta.text\n onDelta(event.delta.text, fullText)\n }\n\n // \"result\" event contains final text\n if (event.type === \"result\" && event.result) {\n const resultText = typeof event.result === \"string\"\n ? event.result\n : event.result\n if (typeof resultText === \"string\" && resultText.length > fullText.length) {\n const delta = resultText.slice(fullText.length)\n fullText = resultText\n if (delta) onDelta(delta, fullText)\n }\n }\n } catch {\n // Not JSON — could be raw text output, append it\n if (line.trim() && !line.startsWith(\"{\")) {\n fullText += line + \"\\n\"\n onDelta(line + \"\\n\", fullText)\n }\n }\n }\n })\n }\n\n const result = await proc\n\n // If we got no streaming content, fall back to stdout\n if (!fullText && result.stdout) {\n fullText = typeof result.stdout === \"string\" ? result.stdout : \"\"\n }\n\n if (result.exitCode !== 0 && !fullText) {\n const stderr = typeof result.stderr === \"string\" ? result.stderr : \"\"\n return {\n content: \"\",\n error: stderr || `Claude Code exited with code ${result.exitCode}`,\n duration: Date.now() - start,\n }\n }\n\n return {\n content: fullText,\n duration: Date.now() - start,\n }\n } catch (error: any) {\n return {\n content: fullText || \"\",\n error: error.message,\n duration: Date.now() - start,\n }\n }\n}\n\n/**\n * Execute a task using the Claude Agent SDK (tier: \"sdk\").\n */\nexport async function executeSdk(\n agent: AgentDef,\n task: AgentTask,\n apiKey: string,\n): Promise<AgentResponse> {\n const start = Date.now()\n\n try {\n // @ts-ignore — SDK may not be installed\n const sdk = await import(\"@anthropic-ai/claude-agent-sdk\")\n const { query } = sdk\n\n const prompt = agent.systemPrompt\n ? `${agent.systemPrompt}\\n\\n${task.message}`\n : task.message\n\n let content = \"\"\n\n const q = query({\n prompt,\n options: {\n model: agent.model,\n cwd: agent.workspace,\n permissionMode: \"bypassPermissions\" as any,\n },\n })\n\n for await (const message of q) {\n if (message.type === \"result\" && message.subtype === \"success\") {\n content = message.result || \"\"\n }\n }\n\n return {\n content,\n duration: Date.now() - start,\n }\n } catch (error: any) {\n return {\n content: \"\",\n error: `SDK error: ${error.message}`,\n duration: Date.now() - start,\n }\n }\n}\n\n/**\n * Execute a task using agentx's own orchestrator (tier: \"orchestrator\").\n */\nexport async function executeOrchestrator(\n agent: AgentDef,\n task: AgentTask,\n apiKey?: string,\n): Promise<AgentResponse> {\n const start = Date.now()\n\n try {\n const { generate } = await import(\"@/agent\")\n const providerName = agent.provider || \"claude-code\"\n\n const result = await generate({\n task: task.message,\n cwd: agent.workspace,\n provider: providerName as any,\n model: agent.model,\n apiKey,\n overwrite: true,\n interactive: false,\n context7: false,\n })\n\n return {\n content: result.content || \"Done.\",\n tokensUsed: result.tokensUsed,\n duration: Date.now() - start,\n }\n } catch (error: any) {\n return {\n content: \"\",\n error: `Orchestrator error: ${error.message}`,\n duration: Date.now() - start,\n }\n }\n}\n\n/**\n * Route a task to the correct execution tier.\n */\nexport async function executeTask(\n agent: AgentDef,\n task: AgentTask,\n providers: Record<string, { apiKey?: string }>,\n onDelta?: StreamCallback,\n historyContext?: string,\n resumeSessionId?: string,\n): Promise<AgentResponse> {\n switch (agent.tier) {\n case \"claude-code\":\n if (onDelta) {\n return executeClaudeCodeStreaming(agent, task, onDelta, historyContext, resumeSessionId)\n }\n return executeClaudeCode(agent, task, historyContext, resumeSessionId)\n\n case \"sdk\": {\n const providerName = agent.provider || \"claude\"\n const apiKey = providers[providerName]?.apiKey\n if (!apiKey) {\n return {\n content: \"\",\n error: `No API key for provider \"${providerName}\". Configure providers.${providerName}.apiKey`,\n }\n }\n return executeSdk(agent, task, apiKey)\n }\n\n case \"orchestrator\": {\n const providerName = agent.provider || \"claude-code\"\n const apiKey = providers[providerName]?.apiKey\n return executeOrchestrator(agent, task, apiKey)\n }\n\n default:\n return {\n content: \"\",\n error: `Unknown tier: ${agent.tier}`,\n }\n }\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, statSync } from \"fs\"\nimport { resolve, join, relative, dirname } from \"path\"\nimport type { WikiArticle, WikiArticleMeta, WikiEntry, WikiIndex, WikiAccess } from \"./types\"\n\n// --- Wiki Store: filesystem-based knowledge base with permissions ---\n//\n// Structure:\n// .agentx/wiki/\n// _index.md # Master index with aliases\n// _backlinks.json # Reverse link index\n// raw/entries/ # One .md per ingested entry\n// {directories}/ # Articles organized by type\n//\n// Permission model:\n// - private: only owner agent reads/writes\n// - shared: owner writes, listed agents read\n// - public: owner writes, all agents read\n\nexport class WikiStore {\n private baseDir: string\n private rawDir: string\n private log: (...args: unknown[]) => void\n\n constructor(\n baseDir: string = resolve(process.cwd(), \".agentx/wiki\"),\n log: (...args: unknown[]) => void = console.error.bind(console, \"[wiki]\"),\n ) {\n this.baseDir = baseDir\n this.rawDir = resolve(baseDir, \"raw/entries\")\n this.log = log\n\n mkdirSync(this.rawDir, { recursive: true })\n mkdirSync(resolve(baseDir, \"raw\"), { recursive: true })\n }\n\n // --- Permission checks ---\n\n /**\n * Check if an agent can read an article.\n */\n canRead(article: WikiArticleMeta, agentId: string): boolean {\n if (article.access === \"public\") return true\n if (article.owner === agentId) return true\n if (article.access === \"shared\" && article.sharedWith?.includes(agentId)) return true\n return false\n }\n\n /**\n * Check if an agent can write an article.\n */\n canWrite(article: WikiArticleMeta, agentId: string): boolean {\n return article.owner === agentId\n }\n\n // --- Raw entries (ingestion) ---\n\n /**\n * Add a raw entry (from a conversation, cron result, etc.)\n */\n addEntry(entry: WikiEntry): string {\n const filename = `${entry.date}_${entry.id}.md`\n const filepath = resolve(this.rawDir, filename)\n\n const frontmatter = [\n \"---\",\n `id: ${entry.id}`,\n `date: ${entry.date}`,\n `agent: ${entry.agentId}`,\n `source: ${entry.source}`,\n ]\n if (entry.sourceContext) frontmatter.push(`context: ${entry.sourceContext}`)\n if (entry.meta) {\n for (const [k, v] of Object.entries(entry.meta)) {\n frontmatter.push(`${k}: ${JSON.stringify(v)}`)\n }\n }\n frontmatter.push(\"---\", \"\", entry.content)\n\n writeFileSync(filepath, frontmatter.join(\"\\n\"))\n return filename\n }\n\n /**\n * List raw entries, optionally filtered by agent or date range.\n */\n listEntries(filter?: { agentId?: string; after?: string; before?: string }): WikiEntry[] {\n if (!existsSync(this.rawDir)) return []\n\n const files = readdirSync(this.rawDir).filter(f => f.endsWith(\".md\")).sort()\n const entries: WikiEntry[] = []\n\n for (const file of files) {\n const content = readFileSync(resolve(this.rawDir, file), \"utf-8\")\n const entry = this.parseEntry(content, file)\n if (!entry) continue\n\n if (filter?.agentId && entry.agentId !== filter.agentId) continue\n if (filter?.after && entry.date < filter.after) continue\n if (filter?.before && entry.date > filter.before) continue\n\n entries.push(entry)\n }\n\n return entries\n }\n\n private parseEntry(content: string, filename: string): WikiEntry | null {\n const fmMatch = content.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/)\n if (!fmMatch) return null\n\n const fm = fmMatch[1]\n const body = fmMatch[2].trim()\n\n const get = (key: string): string => {\n const m = fm.match(new RegExp(`^${key}:\\\\s*(.+)$`, \"m\"))\n return m?.[1]?.trim() || \"\"\n }\n\n return {\n id: get(\"id\") || filename.replace(\".md\", \"\"),\n date: get(\"date\"),\n agentId: get(\"agent\"),\n source: get(\"source\"),\n sourceContext: get(\"context\") || undefined,\n content: body,\n }\n }\n\n // --- Articles (compiled knowledge) ---\n\n /**\n * Write or update a wiki article.\n */\n writeArticle(\n path: string,\n meta: WikiArticleMeta,\n content: string,\n agentId: string,\n ): boolean {\n // Check write permission if article exists\n const existing = this.readArticle(path)\n if (existing && !this.canWrite(existing.meta, agentId)) {\n this.log(`Permission denied: \"${agentId}\" cannot write \"${path}\" (owner: ${existing.meta.owner})`)\n return false\n }\n\n const fullPath = resolve(this.baseDir, path)\n mkdirSync(dirname(fullPath), { recursive: true })\n\n const frontmatter = [\n \"---\",\n `title: \"${meta.title}\"`,\n `type: ${meta.type}`,\n `owner: ${meta.owner}`,\n `access: ${meta.access}`,\n ]\n if (meta.sharedWith?.length) {\n frontmatter.push(`shared_with: [${meta.sharedWith.map(s => `\"${s}\"`).join(\", \")}]`)\n }\n frontmatter.push(\n `created: ${meta.created}`,\n `last_updated: ${meta.lastUpdated}`,\n `related: [${meta.related.map(r => `\"${r}\"`).join(\", \")}]`,\n `sources: [${meta.sources.map(s => `\"${s}\"`).join(\", \")}]`,\n )\n if (meta.tags?.length) {\n frontmatter.push(`tags: [${meta.tags.map(t => `\"${t}\"`).join(\", \")}]`)\n }\n frontmatter.push(\"---\", \"\", content)\n\n writeFileSync(fullPath, frontmatter.join(\"\\n\"))\n return true\n }\n\n /**\n * Read an article. Returns null if not found.\n */\n readArticle(path: string): WikiArticle | null {\n const fullPath = resolve(this.baseDir, path)\n if (!existsSync(fullPath)) return null\n\n const raw = readFileSync(fullPath, \"utf-8\")\n return this.parseArticle(raw, path)\n }\n\n /**\n * Read an article with permission check.\n */\n readArticleAs(path: string, agentId: string): WikiArticle | null {\n const article = this.readArticle(path)\n if (!article) return null\n if (!this.canRead(article.meta, agentId)) return null\n return article\n }\n\n private parseArticle(raw: string, path: string): WikiArticle | null {\n const fmMatch = raw.match(/^---\\n([\\s\\S]*?)\\n---\\n([\\s\\S]*)$/)\n if (!fmMatch) return null\n\n const fm = fmMatch[1]\n const content = fmMatch[2].trim()\n\n const get = (key: string): string => {\n const m = fm.match(new RegExp(`^${key}:\\\\s*(.+)$`, \"m\"))\n return m?.[1]?.trim().replace(/^\"(.*)\"$/, \"$1\") || \"\"\n }\n\n const getArray = (key: string): string[] => {\n const m = fm.match(new RegExp(`^${key}:\\\\s*\\\\[(.*)\\\\]$`, \"m\"))\n if (!m) return []\n return m[1].split(\",\").map(s => s.trim().replace(/^\"(.*)\"$/, \"$1\")).filter(Boolean)\n }\n\n return {\n meta: {\n title: get(\"title\"),\n type: get(\"type\"),\n owner: get(\"owner\"),\n access: (get(\"access\") as WikiAccess) || \"public\",\n sharedWith: getArray(\"shared_with\"),\n created: get(\"created\"),\n lastUpdated: get(\"last_updated\"),\n related: getArray(\"related\"),\n sources: getArray(\"sources\"),\n tags: getArray(\"tags\"),\n },\n content,\n path,\n }\n }\n\n // --- Index and discovery ---\n\n /**\n * List all articles accessible to an agent.\n */\n listArticles(agentId: string): WikiArticle[] {\n const articles: WikiArticle[] = []\n this.walkDir(this.baseDir, (filePath) => {\n if (!filePath.endsWith(\".md\")) return\n const relPath = relative(this.baseDir, filePath)\n if (relPath.startsWith(\"raw/\") || relPath.startsWith(\"_\")) return\n\n const article = this.readArticle(relPath)\n if (article && this.canRead(article.meta, agentId)) {\n articles.push(article)\n }\n })\n return articles\n }\n\n /**\n * Search articles by keyword. Returns articles the agent can read.\n */\n search(query: string, agentId: string, maxResults: number = 10): WikiArticle[] {\n const queryLower = query.toLowerCase()\n const results: Array<{ article: WikiArticle; score: number }> = []\n\n this.walkDir(this.baseDir, (filePath) => {\n if (!filePath.endsWith(\".md\")) return\n const relPath = relative(this.baseDir, filePath)\n if (relPath.startsWith(\"raw/\") || relPath.startsWith(\"_\")) return\n\n const article = this.readArticle(relPath)\n if (!article || !this.canRead(article.meta, agentId)) return\n\n let score = 0\n const titleLower = article.meta.title.toLowerCase()\n const contentLower = article.content.toLowerCase()\n\n // Title match scores highest\n if (titleLower.includes(queryLower)) score += 10\n // Tag match\n if (article.meta.tags?.some(t => t.toLowerCase().includes(queryLower))) score += 5\n // Content match (count occurrences, cap at 5)\n const occurrences = (contentLower.match(new RegExp(queryLower.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\"), \"g\")) || []).length\n score += Math.min(occurrences, 5)\n\n if (score > 0) {\n results.push({ article, score })\n }\n })\n\n return results\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults)\n .map(r => r.article)\n }\n\n /**\n * Find articles relevant to a message (for context injection).\n * Extracts keywords from the message and searches the wiki.\n */\n findRelevant(message: string, agentId: string, maxArticles: number = 3): WikiArticle[] {\n // Extract meaningful keywords (skip common words)\n const stopWords = new Set([\n \"the\", \"a\", \"an\", \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\",\n \"have\", \"has\", \"had\", \"do\", \"does\", \"did\", \"will\", \"would\", \"could\",\n \"should\", \"may\", \"might\", \"can\", \"shall\", \"to\", \"of\", \"in\", \"for\",\n \"on\", \"with\", \"at\", \"by\", \"from\", \"as\", \"into\", \"about\", \"through\",\n \"and\", \"but\", \"or\", \"not\", \"no\", \"if\", \"then\", \"so\", \"what\", \"how\",\n \"when\", \"where\", \"who\", \"which\", \"that\", \"this\", \"it\", \"i\", \"you\",\n \"we\", \"they\", \"he\", \"she\", \"me\", \"my\", \"your\", \"our\", \"their\",\n \"please\", \"just\", \"also\", \"very\", \"much\", \"some\", \"any\", \"all\",\n ])\n\n const words = message.toLowerCase()\n .replace(/[^a-z0-9\\s@_-]/g, \" \")\n .split(/\\s+/)\n .filter(w => w.length > 2 && !stopWords.has(w))\n\n if (words.length === 0) return []\n\n // Score articles by keyword matches\n const articleScores = new Map<string, { article: WikiArticle; score: number }>()\n\n for (const word of words) {\n const matches = this.search(word, agentId, 5)\n for (const article of matches) {\n const existing = articleScores.get(article.path)\n if (existing) {\n existing.score += 1\n } else {\n articleScores.set(article.path, { article, score: 1 })\n }\n }\n }\n\n return Array.from(articleScores.values())\n .sort((a, b) => b.score - a.score)\n .slice(0, maxArticles)\n .map(r => r.article)\n }\n\n /**\n * Build context string from relevant wiki articles for prompt injection.\n * Token-efficient: includes title + first ~500 chars of each article.\n */\n buildContext(articles: WikiArticle[], maxChars: number = 4000): string {\n if (articles.length === 0) return \"\"\n\n const lines: string[] = [\"[Wiki Knowledge]\"]\n\n let totalChars = 0\n for (const article of articles) {\n const header = `\\n## ${article.meta.title} (${article.meta.type})`\n const body = article.content.length > 600\n ? article.content.slice(0, 600) + \"...\"\n : article.content\n\n const chunk = header + \"\\n\" + body\n if (totalChars + chunk.length > maxChars) break\n\n lines.push(chunk)\n totalChars += chunk.length\n }\n\n lines.push(\"\\n[End Wiki Knowledge]\")\n return lines.join(\"\\n\")\n }\n\n /**\n * Rebuild the master index.\n */\n rebuildIndex(): WikiIndex {\n const articles: WikiIndex[\"articles\"] = []\n const backlinks = new Map<string, number>()\n\n this.walkDir(this.baseDir, (filePath) => {\n if (!filePath.endsWith(\".md\")) return\n const relPath = relative(this.baseDir, filePath)\n if (relPath.startsWith(\"raw/\") || relPath.startsWith(\"_\")) return\n\n const article = this.readArticle(relPath)\n if (!article) return\n\n // Count wikilinks for backlinks\n const links = article.content.match(/\\[\\[([^\\]]+)\\]\\]/g) || []\n for (const link of links) {\n const target = link.replace(/\\[\\[|\\]\\]/g, \"\")\n backlinks.set(target, (backlinks.get(target) || 0) + 1)\n }\n\n // Extract aliases from title and tags\n const aliases = [article.meta.title.toLowerCase()]\n if (article.meta.tags) {\n aliases.push(...article.meta.tags.map(t => t.toLowerCase()))\n }\n\n articles.push({\n path: relPath,\n title: article.meta.title,\n type: article.meta.type,\n owner: article.meta.owner,\n access: article.meta.access,\n sharedWith: article.meta.sharedWith,\n aliases,\n backlinks: backlinks.get(article.meta.title) || 0,\n })\n })\n\n const index: WikiIndex = {\n articles,\n lastRebuilt: new Date().toISOString(),\n }\n\n // Write index files\n writeFileSync(\n resolve(this.baseDir, \"_index.json\"),\n JSON.stringify(index, null, 2),\n )\n\n // Write human-readable WIKI.md\n const md = [\"# Wiki Index\", \"\", `Last rebuilt: ${index.lastRebuilt}`, \"\"]\n const byType = new Map<string, typeof articles>()\n for (const a of articles) {\n const list = byType.get(a.type) || []\n list.push(a)\n byType.set(a.type, list)\n }\n\n for (const [type, list] of Array.from(byType.entries()).sort()) {\n md.push(`## ${type}`, \"\")\n for (const a of list.sort((x, y) => x.title.localeCompare(y.title))) {\n const access = a.access === \"private\" ? \" (private)\" : a.access === \"shared\" ? \" (shared)\" : \"\"\n md.push(`- [${a.title}](${a.path})${access} — owner: ${a.owner}`)\n }\n md.push(\"\")\n }\n\n writeFileSync(resolve(this.baseDir, \"WIKI.md\"), md.join(\"\\n\"))\n\n this.log(`Index rebuilt: ${articles.length} articles`)\n return index\n }\n\n /**\n * Get wiki stats.\n */\n stats(): {\n totalArticles: number\n totalEntries: number\n articlesByType: Record<string, number>\n articlesByAccess: Record<string, number>\n articlesByOwner: Record<string, number>\n } {\n let totalArticles = 0\n const byType: Record<string, number> = {}\n const byAccess: Record<string, number> = {}\n const byOwner: Record<string, number> = {}\n\n this.walkDir(this.baseDir, (filePath) => {\n if (!filePath.endsWith(\".md\")) return\n const relPath = relative(this.baseDir, filePath)\n if (relPath.startsWith(\"raw/\") || relPath.startsWith(\"_\") || relPath === \"WIKI.md\") return\n\n const article = this.readArticle(relPath)\n if (!article) return\n\n totalArticles++\n byType[article.meta.type] = (byType[article.meta.type] || 0) + 1\n byAccess[article.meta.access] = (byAccess[article.meta.access] || 0) + 1\n byOwner[article.meta.owner] = (byOwner[article.meta.owner] || 0) + 1\n })\n\n const entryFiles = existsSync(this.rawDir)\n ? readdirSync(this.rawDir).filter(f => f.endsWith(\".md\")).length\n : 0\n\n return {\n totalArticles,\n totalEntries: entryFiles,\n articlesByType: byType,\n articlesByAccess: byAccess,\n articlesByOwner: byOwner,\n }\n }\n\n // --- Helpers ---\n\n private walkDir(dir: string, callback: (filePath: string) => void): void {\n if (!existsSync(dir)) return\n for (const entry of readdirSync(dir)) {\n const full = join(dir, entry)\n const stat = statSync(full)\n if (stat.isDirectory()) {\n this.walkDir(full, callback)\n } else {\n callback(full)\n }\n }\n }\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\n\n// --- Conversation session store ---\n// One session per agent + channel + chatId + day.\n// For claude-code tier: stores the Claude session ID so we can --resume it.\n// For other tiers: stores message history as text, prepended to each prompt.\n\nexport interface SessionMessage {\n role: \"user\" | \"agent\"\n name?: string // sender name or agent name\n content: string\n timestamp: string\n}\n\nexport interface Session {\n id: string\n agentId: string\n channel: string\n chatId: string\n day: string // YYYY-MM-DD\n claudeSessionId?: string // Claude Code native session ID (for --resume)\n messages: SessionMessage[]\n createdAt: string\n updatedAt: string\n}\n\nconst MAX_HISTORY_CHARS = 12000 // Keep last ~12k chars of history to fit in context\nconst MAX_MESSAGES = 30 // Keep last 30 messages max\n\nexport class SessionStore {\n private sessionsDir: string\n private cache: Map<string, Session> = new Map()\n\n constructor(baseDir: string = process.cwd()) {\n this.sessionsDir = resolve(baseDir, \".agentx/sessions\")\n if (!existsSync(this.sessionsDir)) {\n mkdirSync(this.sessionsDir, { recursive: true })\n }\n }\n\n /**\n * Build a deterministic session key.\n */\n private sessionKey(agentId: string, channel: string, chatId: string): string {\n const day = new Date().toISOString().slice(0, 10) // YYYY-MM-DD\n return `${agentId}:${channel}:${chatId}:${day}`\n }\n\n private sessionFile(key: string): string {\n // Sanitize key for filesystem\n const safe = key.replace(/[^a-zA-Z0-9_:-]/g, \"_\")\n return resolve(this.sessionsDir, `${safe}.json`)\n }\n\n /**\n * Get or create a session for this agent+channel+chat+day.\n */\n getSession(agentId: string, channel: string, chatId: string): Session {\n const key = this.sessionKey(agentId, channel, chatId)\n\n // Check cache\n if (this.cache.has(key)) {\n return this.cache.get(key)!\n }\n\n // Try loading from disk\n const file = this.sessionFile(key)\n if (existsSync(file)) {\n try {\n const data = JSON.parse(readFileSync(file, \"utf-8\")) as Session\n this.cache.set(key, data)\n return data\n } catch {\n // Corrupted file — start fresh\n }\n }\n\n // Create new session\n const day = new Date().toISOString().slice(0, 10)\n const session: Session = {\n id: key,\n agentId,\n channel,\n chatId,\n day,\n messages: [],\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n }\n\n this.cache.set(key, session)\n this.save(session)\n return session\n }\n\n /**\n * Add a user message to the session.\n */\n addUserMessage(agentId: string, channel: string, chatId: string, senderName: string, content: string): void {\n const session = this.getSession(agentId, channel, chatId)\n session.messages.push({\n role: \"user\",\n name: senderName,\n content,\n timestamp: new Date().toISOString(),\n })\n this.trim(session)\n session.updatedAt = new Date().toISOString()\n this.save(session)\n }\n\n /**\n * Add an agent response to the session.\n */\n addAgentMessage(agentId: string, channel: string, chatId: string, content: string): void {\n const session = this.getSession(agentId, channel, chatId)\n session.messages.push({\n role: \"agent\",\n name: agentId,\n content,\n timestamp: new Date().toISOString(),\n })\n this.trim(session)\n session.updatedAt = new Date().toISOString()\n this.save(session)\n }\n\n /**\n * Get the Claude Code session ID for this conversation (for --resume).\n * Returns undefined if no session yet (first message of the day).\n */\n getClaudeSessionId(agentId: string, channel: string, chatId: string): string | undefined {\n const session = this.getSession(agentId, channel, chatId)\n return session.claudeSessionId\n }\n\n /**\n * Store the Claude Code session ID after first invocation.\n */\n setClaudeSessionId(agentId: string, channel: string, chatId: string, claudeSessionId: string): void {\n const session = this.getSession(agentId, channel, chatId)\n session.claudeSessionId = claudeSessionId\n session.updatedAt = new Date().toISOString()\n this.save(session)\n }\n\n /**\n * Build conversation history string to prepend to the prompt.\n * Returns empty string if no history.\n * Used for non-claude-code tiers that don't have native sessions.\n */\n buildHistoryContext(agentId: string, channel: string, chatId: string): string {\n const session = this.getSession(agentId, channel, chatId)\n if (session.messages.length === 0) return \"\"\n\n const lines: string[] = [\n `[Conversation history for today (${session.day})]`,\n ]\n\n for (const msg of session.messages) {\n const time = msg.timestamp.slice(11, 16) // HH:MM\n if (msg.role === \"user\") {\n lines.push(`[${time}] ${msg.name || \"User\"}: ${msg.content}`)\n } else {\n lines.push(`[${time}] ${msg.name || \"Agent\"}: ${msg.content}`)\n }\n }\n\n lines.push(\"[End of history — respond to the latest message above]\")\n lines.push(\"\")\n\n return lines.join(\"\\n\")\n }\n\n /**\n * Trim session to stay within limits.\n */\n private trim(session: Session): void {\n // Trim by message count\n if (session.messages.length > MAX_MESSAGES) {\n session.messages = session.messages.slice(-MAX_MESSAGES)\n }\n\n // Trim by total character count\n let totalChars = session.messages.reduce((sum, m) => sum + m.content.length, 0)\n while (totalChars > MAX_HISTORY_CHARS && session.messages.length > 2) {\n const removed = session.messages.shift()!\n totalChars -= removed.content.length\n }\n }\n\n private save(session: Session): void {\n try {\n const file = this.sessionFile(session.id)\n writeFileSync(file, JSON.stringify(session, null, 2))\n } catch {\n // Best-effort persistence\n }\n }\n}\n","import type { DaemonConfig, AgentDef } from \"@/daemon/config\"\nimport { executeTask, type AgentTask, type AgentResponse, type StreamCallback, type AgentPeer } from \"./runtime\"\nimport { SessionStore } from \"./sessions\"\nimport { WikiStore } from \"@/wiki\"\n\n// --- Agent Registry: lifecycle management + concurrency control ---\n\ninterface AgentState {\n id: string\n def: AgentDef\n activeTasks: number\n totalTasks: number\n lastActive?: Date\n errors: number\n}\n\nexport class AgentRegistry {\n private agents: Map<string, AgentState> = new Map()\n private config: DaemonConfig\n private providers: Record<string, { apiKey?: string }> = {}\n private sessions: SessionStore\n private wiki: WikiStore\n private log: (...args: unknown[]) => void\n\n constructor(\n config: DaemonConfig,\n log: (...args: unknown[]) => void = console.error.bind(console, \"[agents]\"),\n ) {\n this.log = log\n this.config = config\n this.providers = config.providers\n this.sessions = new SessionStore()\n this.wiki = new WikiStore()\n\n for (const [id, def] of Object.entries(config.agents)) {\n this.agents.set(id, {\n id,\n def,\n activeTasks: 0,\n totalTasks: 0,\n errors: 0,\n })\n }\n }\n\n /**\n * Get agent definition by ID.\n */\n getAgent(id: string): AgentDef | undefined {\n return this.agents.get(id)?.def\n }\n\n /**\n * Find agent by mention pattern (e.g., \"@nadia\" -> \"marketing-agent\").\n * Returns the agent with the longest (most specific) mention match.\n */\n findByMention(text: string): string | undefined {\n const lower = text.toLowerCase()\n let bestId: string | undefined\n let bestLen = 0\n\n for (const [id, state] of this.agents) {\n for (const mention of state.def.mentions) {\n const mentionLower = mention.toLowerCase()\n if (lower.includes(mentionLower) && mentionLower.length > bestLen) {\n bestId = id\n bestLen = mentionLower.length\n }\n }\n }\n\n return bestId\n }\n\n /**\n * Find ALL agents mentioned in text (for bot-to-bot detection).\n */\n findAllMentioned(text: string): string[] {\n const lower = text.toLowerCase()\n const found: string[] = []\n\n for (const [id, state] of this.agents) {\n for (const mention of state.def.mentions) {\n if (lower.includes(mention.toLowerCase())) {\n found.push(id)\n break\n }\n }\n }\n\n return found\n }\n\n /**\n * Get the primary channel handle for an agent (e.g. \"@noqta_devops_bot\" on telegram).\n */\n private getChannelHandle(agentId: string, channel?: string): string | undefined {\n const agent = this.agents.get(agentId)?.def\n if (!agent) return undefined\n\n // For telegram, find the mention that starts with @ (bot username)\n if (channel === \"telegram\") {\n return agent.mentions.find((m) => m.startsWith(\"@\"))\n }\n\n // Fallback: first mention\n return agent.mentions[0]\n }\n\n /**\n * Enrich the task context with peer roster and channel handles.\n */\n private enrichTaskContext(task: AgentTask): AgentTask {\n const channel = task.context?.channel\n\n // Build peer list (all agents except self)\n const peers: AgentPeer[] = []\n for (const [id, state] of this.agents) {\n if (id === task.agentId) continue\n peers.push({\n id,\n name: state.def.name,\n handle: this.getChannelHandle(id, channel),\n role: state.def.systemPrompt?.split(\"\\n\")[0]?.slice(0, 100),\n })\n }\n\n // Get own handle\n const myHandle = this.getChannelHandle(task.agentId, channel)\n\n return {\n ...task,\n context: {\n ...task.context,\n myHandle,\n peers,\n },\n }\n }\n\n /**\n * Execute a task on an agent. Respects maxConcurrent limit.\n */\n async execute(task: AgentTask, onDelta?: StreamCallback): Promise<AgentResponse> {\n const state = this.agents.get(task.agentId)\n if (!state) {\n return { content: \"\", error: `Unknown agent: ${task.agentId}` }\n }\n\n if (state.activeTasks >= state.def.maxConcurrent) {\n return {\n content: \"\",\n error: `Agent \"${task.agentId}\" is busy (${state.activeTasks}/${state.def.maxConcurrent} tasks)`,\n }\n }\n\n state.activeTasks++\n state.totalTasks++\n state.lastActive = new Date()\n\n this.log(`[${task.agentId}] executing task (${state.activeTasks}/${state.def.maxConcurrent})`)\n\n // Build conversation history for session continuity\n const channel = task.context?.channel || \"api\"\n const chatId = task.context?.group || task.context?.sender || \"default\"\n const senderName = task.context?.sender || \"User\"\n\n // Record user message in session\n this.sessions.addUserMessage(task.agentId, channel, chatId, senderName, task.message)\n\n // Enrich task context with peer info and channel handles\n task = this.enrichTaskContext(task)\n\n // Wiki: find relevant articles and inject as context (token-efficient)\n const wikiArticles = this.wiki.findRelevant(task.message, task.agentId, 3)\n const wikiContext = this.wiki.buildContext(wikiArticles)\n\n // Session continuity:\n // - claude-code tier: --resume SESSION_ID (native, carries full context)\n // - other tiers: inject conversation history as text\n const resumeSessionId = state.def.tier === \"claude-code\"\n ? this.sessions.getClaudeSessionId(task.agentId, channel, chatId)\n : undefined\n\n const sessionHistory = !resumeSessionId\n ? this.sessions.buildHistoryContext(task.agentId, channel, chatId)\n : undefined\n\n // Combine wiki + history (wiki always included, history only when no --resume)\n const historyContext = [wikiContext, sessionHistory].filter(Boolean).join(\"\\n\\n\") || undefined\n\n try {\n const response = await executeTask(state.def, task, this.providers, onDelta, historyContext, resumeSessionId)\n\n if (response.error) {\n state.errors++\n this.log(`[${task.agentId}] error: ${response.error}`)\n } else {\n // Record agent response in session\n this.sessions.addAgentMessage(task.agentId, channel, chatId, response.content)\n\n // Store Claude session ID for future --resume\n if (response.claudeSessionId) {\n this.sessions.setClaudeSessionId(task.agentId, channel, chatId, response.claudeSessionId)\n }\n\n // Wiki: export conversation as raw entry for later absorption\n if (response.content.length > 50) {\n try {\n const entryId = `${task.agentId}-${Date.now().toString(36)}`\n this.wiki.addEntry({\n id: entryId,\n date: new Date().toISOString().slice(0, 10),\n agentId: task.agentId,\n source: channel,\n sourceContext: task.context?.group || task.context?.sender,\n content: `User: ${task.message}\\n\\nAgent: ${response.content}`,\n })\n } catch {\n // Wiki export is best-effort\n }\n }\n\n this.log(\n `[${task.agentId}] completed in ${response.duration}ms` +\n (response.tokensUsed ? ` (${response.tokensUsed} tokens)` : \"\"),\n )\n }\n\n return response\n } catch (error: any) {\n state.errors++\n this.log(`[${task.agentId}] unexpected error: ${error.message}`)\n return { content: \"\", error: error.message }\n } finally {\n state.activeTasks--\n }\n }\n\n /**\n * List all agents and their status.\n */\n list(): Array<{\n id: string\n name: string\n tier: string\n workspace: string\n active: number\n total: number\n errors: number\n lastActive?: Date\n }> {\n return Array.from(this.agents.values()).map((s) => ({\n id: s.id,\n name: s.def.name,\n tier: s.def.tier,\n workspace: s.def.workspace,\n active: s.activeTasks,\n total: s.totalTasks,\n errors: s.errors,\n lastActive: s.lastActive,\n }))\n }\n}\n","import type { DaemonConfig } from \"@/daemon/config\"\nimport type { AgentRegistry } from \"@/agents/registry\"\nimport type { A2AMesh } from \"@/a2a/mesh\"\nimport type { ChannelAdapter, IncomingMessage } from \"./types\"\nimport type { TelegramAdapter } from \"./telegram\"\nimport type { HookRegistry } from \"@/hooks\"\n\n// --- Message Router ---\n// Routes channel messages to agents. Supports:\n// - Typing indicator while processing\n// - Streaming response edits\n// - Seen reaction (👀) on mention\n// - Bot-to-bot: if response mentions another agent, route it\n// - Correct bot account sends the reply (not always the first one)\n\nconst STREAM_EDIT_INTERVAL_MS = 1500\nconst TYPING_INTERVAL_MS = 4000\n\n// Group conversation log entry\ninterface GroupLogEntry {\n sender: string // \"User Name\" or \"agent:agent-id\"\n text: string\n timestamp: number\n}\n\nconst GROUP_LOG_MAX_ENTRIES = 20\nconst GROUP_LOG_MAX_CHARS = 6000\n\nexport class MessageRouter {\n private registry: AgentRegistry\n private config: DaemonConfig\n private channels: Map<string, ChannelAdapter> = new Map()\n private hooks?: HookRegistry\n private mesh?: A2AMesh\n private groupLogs: Map<string, GroupLogEntry[]> = new Map() // chatId -> recent messages\n private log: (...args: unknown[]) => void\n\n constructor(\n registry: AgentRegistry,\n config: DaemonConfig,\n hooks?: HookRegistry,\n log: (...args: unknown[]) => void = console.error.bind(console, \"[router]\"),\n ) {\n this.registry = registry\n this.config = config\n this.hooks = hooks\n this.log = log\n }\n\n setMesh(mesh: A2AMesh): void {\n this.mesh = mesh\n }\n\n addChannel(adapter: ChannelAdapter): void {\n this.channels.set(adapter.name, adapter)\n adapter.onMessage((msg) => this.handleMessage(adapter, msg))\n }\n\n async startAll(): Promise<void> {\n for (const [name, adapter] of this.channels) {\n this.log(`Starting channel: ${name}`)\n await adapter.start()\n }\n }\n\n async stopAll(): Promise<void> {\n for (const [name, adapter] of this.channels) {\n this.log(`Stopping channel: ${name}`)\n await adapter.stop()\n }\n }\n\n private async handleMessage(\n adapter: ChannelAdapter,\n msg: IncomingMessage,\n ): Promise<void> {\n // Pre-hook\n if (this.hooks?.has(\"pre:channel-message\" as any)) {\n const hookResult = await this.hooks.execute(\"pre:channel-message\" as any, {\n event: \"pre:channel-message\" as any,\n channel: msg.channel,\n sender: msg.sender.name,\n text: msg.text,\n group: msg.group?.name,\n })\n\n if (hookResult.blocked) {\n this.log(`Message blocked by hook: ${hookResult.message}`)\n return\n }\n\n if (hookResult.modified?.text) {\n msg = { ...msg, text: hookResult.modified.text as string }\n }\n }\n\n // Log ALL group messages for conversation context (before agent resolution)\n if (msg.group) {\n const chatId = msg.group.id\n this.logGroupMessage(chatId, msg.sender.name, msg.text)\n }\n\n // Resolve agent — check local first, then mesh peers\n const agentId = this.resolveAgent(msg)\n\n if (!agentId) {\n return\n }\n\n // Dedup: in groups, multiple bot accounts receive the same message.\n // Only the account BOUND to this agent should handle it.\n if (msg.group && msg.channel === \"telegram\") {\n const boundAccount = this.getAccountForAgent(agentId)\n if (boundAccount && boundAccount !== msg.accountId) {\n return\n }\n }\n\n const chatId = msg.group?.id || msg.sender.id\n const agentDef = this.registry.getAgent(agentId)\n const agentName = agentDef?.name || agentId\n\n // Determine which bot account should send the response\n const replyAccountId = this.getAccountForAgent(agentId) || msg.accountId\n\n this.log(\n `Routing [${msg.channel}/${msg.sender.name}] -> \"${agentName}\": ${msg.text.slice(0, 80)}`,\n )\n\n // React with 👀 to acknowledge\n this.adapterReact(adapter, chatId, msg.id, \"👀\", replyAccountId)\n\n // Start typing indicator loop (from the correct bot)\n const typingTimer = this.startTypingLoop(adapter, chatId, replyAccountId)\n\n // Streaming setup\n const canStream = typeof adapter.editMessage === \"function\"\n let sentMessageId: string | undefined\n let lastEditTime = 0\n\n const onDelta = canStream\n ? async (_delta: string, fullText: string) => {\n const now = Date.now()\n if (now - lastEditTime < STREAM_EDIT_INTERVAL_MS) return\n\n if (!sentMessageId) {\n const preview = fullText.length > 20\n ? fullText\n : `_${agentName} is writing..._\\n\\n${fullText}`\n try {\n sentMessageId = await this.adapterSend(adapter, {\n channel: msg.channel,\n chatId,\n text: preview,\n replyTo: msg.id,\n accountId: replyAccountId,\n })\n lastEditTime = now\n } catch { /* retry next delta */ }\n } else {\n try {\n await this.adapterEdit(adapter, chatId, sentMessageId, fullText, undefined, replyAccountId)\n lastEditTime = now\n } catch { /* retry next delta */ }\n }\n }\n : undefined\n\n // Build group conversation context (recent messages from the group)\n const groupContext = msg.group ? this.buildGroupContext(chatId) : \"\"\n const messageWithContext = groupContext\n ? `${groupContext}\\n\\n${msg.sender.name}: ${msg.text}`\n : msg.text\n\n // Execute agent task\n const response = await this.registry.execute(\n {\n message: messageWithContext,\n agentId,\n context: {\n channel: msg.channel,\n sender: msg.sender.name,\n group: msg.group?.name,\n mediaPath: msg.media?.path,\n mediaType: msg.media?.type,\n replyToText: msg.replyToText,\n },\n },\n onDelta,\n )\n\n clearInterval(typingTimer)\n\n if (response.error) {\n this.log(`Agent error: ${response.error}`)\n const errorText = `Error: ${response.error}`\n if (sentMessageId) {\n await this.adapterEdit(adapter, chatId, sentMessageId, errorText, \"plain\", replyAccountId)\n } else {\n await this.adapterSend(adapter, {\n channel: msg.channel,\n chatId,\n text: errorText,\n replyTo: msg.id,\n parseMode: \"plain\",\n accountId: replyAccountId,\n })\n }\n return\n }\n\n // Post-hook\n let responseText = response.content\n if (this.hooks?.has(\"post:channel-message\" as any)) {\n const hookResult = await this.hooks.execute(\"post:channel-message\" as any, {\n event: \"post:channel-message\" as any,\n channel: msg.channel,\n sender: msg.sender.name,\n response: responseText,\n agentId,\n })\n\n if (hookResult.blocked) {\n this.log(`Response blocked by hook: ${hookResult.message}`)\n return\n }\n\n if (hookResult.modified?.response) {\n responseText = hookResult.modified.response as string\n }\n }\n\n // Final message\n let sentResponseId: string | undefined\n if (responseText) {\n if (sentMessageId) {\n await this.adapterEdit(adapter, chatId, sentMessageId, responseText, undefined, replyAccountId)\n sentResponseId = sentMessageId\n } else {\n sentResponseId = await this.adapterSend(adapter, {\n channel: msg.channel,\n chatId,\n text: responseText,\n replyTo: msg.id,\n accountId: replyAccountId,\n })\n }\n }\n\n // Log bot response in group conversation\n if (msg.group && responseText) {\n this.logGroupMessage(chatId, agentName, responseText)\n }\n\n // Bot-to-bot: if response mentions another agent, route it\n if (responseText && sentResponseId) {\n this.handleBotToBotChain(adapter, msg, agentId, responseText, sentResponseId, 0).catch((e) => {\n this.log(`Bot-to-bot error: ${e.message}`)\n })\n }\n }\n\n private static readonly MAX_BOT_CHAIN_DEPTH = 3\n\n /**\n * Bot-to-bot conversation chain.\n * When an agent's response mentions another agent, route it and continue\n * the chain if the target agent also mentions someone (up to MAX depth).\n */\n private async handleBotToBotChain(\n adapter: ChannelAdapter,\n originalMsg: IncomingMessage,\n sourceAgentId: string,\n responseText: string,\n responseMessageId: string,\n depth: number,\n ): Promise<void> {\n if (depth >= MessageRouter.MAX_BOT_CHAIN_DEPTH) {\n this.log(`Bot-to-bot: max chain depth (${depth}) reached, stopping`)\n return\n }\n\n for (const [id, def] of Object.entries(this.config.agents)) {\n if (id === sourceAgentId) continue\n\n const mentioned = def.mentions.some((m: string) =>\n responseText.toLowerCase().includes(m.toLowerCase()),\n )\n if (!mentioned) continue\n\n this.log(`Bot-to-bot [${depth + 1}]: \"${sourceAgentId}\" -> \"${id}\"`)\n\n const chatId = originalMsg.group?.id || originalMsg.sender.id\n const targetAccountId = this.getAccountForAgent(id)\n const sourceAccountId = this.getAccountForAgent(sourceAgentId)\n\n try {\n // Target bot reacts 👀 to the source bot's message\n this.adapterReact(adapter, chatId, responseMessageId, \"👀\", targetAccountId)\n\n // Target bot shows typing\n const typingTimer = this.startTypingLoop(adapter, chatId, targetAccountId)\n\n // Include original user message as context so target bot knows the full picture\n const contextMessage = depth === 0\n ? `[Original from ${originalMsg.sender.name}]: ${originalMsg.text}\\n\\n[${sourceAgentId} said]: ${responseText}`\n : responseText\n\n const response = await this.registry.execute({\n message: contextMessage,\n agentId: id,\n context: {\n channel: originalMsg.channel,\n sender: `agent:${sourceAgentId}`,\n group: originalMsg.group?.name,\n },\n })\n\n clearInterval(typingTimer)\n\n if (response.content && !response.error) {\n const sentId = await this.adapterSend(adapter, {\n channel: originalMsg.channel,\n chatId,\n text: response.content,\n accountId: targetAccountId,\n })\n\n // Chain: check if this response also mentions another agent\n if (sentId && response.content) {\n await this.handleBotToBotChain(\n adapter, originalMsg, id, response.content, sentId as string, depth + 1,\n )\n }\n } else if (response.error) {\n this.log(`Bot-to-bot \"${id}\" error: ${response.error}`)\n }\n } catch (e: any) {\n this.log(`Bot-to-bot \"${id}\" failed: ${e.message}`)\n }\n\n break // Route to first mentioned agent per level\n }\n }\n\n // --- Adapter helpers that pass accountId for Telegram ---\n\n private async adapterSend(\n adapter: ChannelAdapter,\n msg: { channel: string; chatId: string; text: string; replyTo?: string; parseMode?: string; accountId?: string },\n ): Promise<string> {\n // For Telegram, pass accountId so the correct bot sends the message\n if (adapter.name === \"telegram\" && msg.accountId) {\n return (adapter as TelegramAdapter).send({\n ...msg,\n parseMode: msg.parseMode as any,\n accountId: msg.accountId,\n }) as Promise<string>\n }\n return (adapter.send(msg as any) || \"\") as Promise<string>\n }\n\n private async adapterEdit(\n adapter: ChannelAdapter,\n chatId: string,\n messageId: string,\n text: string,\n parseMode?: string,\n accountId?: string,\n ): Promise<boolean> {\n if (adapter.name === \"telegram\" && accountId) {\n return (adapter as TelegramAdapter).editMessage(chatId, messageId, text, parseMode, accountId)\n }\n return adapter.editMessage?.(chatId, messageId, text, parseMode) ?? false\n }\n\n private adapterReact(\n adapter: ChannelAdapter,\n chatId: string,\n messageId: string,\n emoji: string,\n accountId?: string,\n ): void {\n if (adapter.name === \"telegram\" && accountId) {\n (adapter as TelegramAdapter).react(chatId, messageId, emoji, accountId)\n } else {\n adapter.react?.(chatId, messageId, emoji)\n }\n }\n\n private startTypingLoop(\n adapter: ChannelAdapter,\n chatId: string,\n accountId?: string,\n ): ReturnType<typeof setInterval> {\n const sendTyping = () => {\n if (adapter.name === \"telegram\" && accountId) {\n (adapter as TelegramAdapter).sendTyping(chatId, accountId)\n } else {\n adapter.sendTyping?.(chatId)\n }\n }\n\n sendTyping()\n return setInterval(sendTyping, TYPING_INTERVAL_MS)\n }\n\n // --- Agent resolution ---\n\n /**\n * Handle a message by routing to a mesh peer's agent.\n * Searches peer agent cards for mention matches.\n */\n private async handleViaMesh(\n adapter: ChannelAdapter,\n msg: IncomingMessage,\n ): Promise<boolean> {\n if (!this.mesh) return false\n\n const textLower = msg.text.toLowerCase()\n const directory = this.mesh.directory()\n\n for (const peer of directory) {\n if (!peer.healthy) continue\n\n for (const skill of peer.skills) {\n // Check if the message mentions this remote agent by name or ID\n if (\n textLower.includes(skill.id.toLowerCase()) ||\n textLower.includes(skill.name.toLowerCase())\n ) {\n this.log(`Mesh routing [${msg.channel}/${msg.sender.name}] -> peer \"${peer.peer}\" agent \"${skill.id}\"`)\n\n const chatId = msg.group?.id || msg.sender.id\n const replyAccountId = msg.accountId\n\n // React + typing\n this.adapterReact(adapter, chatId, msg.id, \"👀\", replyAccountId)\n const typingTimer = this.startTypingLoop(adapter, chatId, replyAccountId)\n\n try {\n const response = await this.mesh.sendTask(peer.peer, msg.text, skill.id)\n\n clearInterval(typingTimer)\n\n if (response) {\n // Prefix with remote agent name so user knows who's responding\n const header = `**${skill.name}** _(${peer.peer})_:\\n\\n`\n await this.adapterSend(adapter, {\n channel: msg.channel,\n chatId,\n text: header + response,\n replyTo: msg.id,\n accountId: replyAccountId,\n })\n }\n\n return true\n } catch (e: any) {\n clearInterval(typingTimer)\n this.log(`Mesh routing error: ${e.message}`)\n\n await this.adapterSend(adapter, {\n channel: msg.channel,\n chatId,\n text: `Error from ${peer.peer}/${skill.name}: ${e.message}`,\n replyTo: msg.id,\n parseMode: \"plain\",\n accountId: replyAccountId,\n })\n return true\n }\n }\n }\n }\n\n return false\n }\n\n // --- Group conversation log ---\n\n /**\n * Log a message in the group conversation history.\n */\n private logGroupMessage(chatId: string, sender: string, text: string): void {\n if (!chatId) return\n const log = this.groupLogs.get(chatId) || []\n log.push({ sender, text: text.slice(0, 500), timestamp: Date.now() })\n\n // Trim to max entries\n while (log.length > GROUP_LOG_MAX_ENTRIES) log.shift()\n\n this.groupLogs.set(chatId, log)\n }\n\n /**\n * Build group conversation context for an agent.\n * Returns recent messages from the group so the agent knows what's been discussed.\n */\n private buildGroupContext(chatId: string): string {\n const log = this.groupLogs.get(chatId)\n if (!log || log.length <= 1) return \"\"\n\n const lines: string[] = [\"[Recent group conversation]\"]\n let chars = 0\n\n // Walk backwards from most recent, skip the very last (it's the current message)\n for (let i = log.length - 2; i >= 0; i--) {\n const entry = log[i]\n const line = `${entry.sender}: ${entry.text}`\n if (chars + line.length > GROUP_LOG_MAX_CHARS) break\n lines.splice(1, 0, line) // Insert at position 1 (after header)\n chars += line.length\n }\n\n if (lines.length <= 1) return \"\"\n lines.push(\"[End of conversation — respond to the latest message]\")\n return lines.join(\"\\n\")\n }\n\n private getAccountForAgent(agentId: string): string | undefined {\n for (const [accountId, account] of Object.entries(this.config.channels.telegram.accounts)) {\n if (account.agentBinding === agentId) {\n return accountId\n }\n }\n return undefined\n }\n\n private resolveAgent(msg: IncomingMessage): string | undefined {\n // Pre-resolved by channel adapter (WhatsApp route-based, etc.)\n if (msg.resolvedAgent) {\n return msg.resolvedAgent\n }\n\n // DM: route to the account's bound agent\n if (!msg.group) {\n if (msg.channel === \"telegram\") {\n const account = this.config.channels.telegram.accounts[msg.accountId]\n return account?.agentBinding\n }\n if (msg.channel === \"whatsapp\") {\n return this.config.channels.whatsapp.defaultAgent\n }\n return undefined\n }\n\n // Group: check policy\n if (msg.channel === \"telegram\") {\n const policy = this.config.channels.telegram.policy\n if (policy.group === \"mention-required\") {\n const agentId = this.registry.findByMention(msg.text)\n if (!agentId) return undefined\n return agentId\n }\n }\n\n // Default: mention matching, then account binding\n const mentionAgent = this.registry.findByMention(msg.text)\n if (mentionAgent) return mentionAgent\n\n if (msg.channel === \"telegram\") {\n const account = this.config.channels.telegram.accounts[msg.accountId]\n return account?.agentBinding\n }\n\n return this.config.channels.whatsapp.defaultAgent\n }\n}\n","// --- Convert standard Markdown to Telegram HTML ---\n//\n// Uses parse_mode: \"HTML\" (not MarkdownV2) — much simpler and more reliable.\n// Based on OpenClaw's approach: markdown → HTML tags.\n//\n// Supported Telegram HTML tags:\n// <b>bold</b>, <i>italic</i>, <s>strikethrough</s>,\n// <code>inline code</code>, <pre><code>code block</code></pre>,\n// <a href=\"url\">link</a>, <blockquote>quote</blockquote>,\n// <tg-spoiler>spoiler</tg-spoiler>\n//\n// Tables are converted to bullet-point format (Telegram has no table support).\n// File extensions that look like TLDs are wrapped in <code> to prevent\n// Telegram generating spurious link previews.\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n}\n\n/**\n * Convert standard Markdown (Claude output) to Telegram HTML.\n */\nexport function markdownToTelegramHtml(md: string): string {\n const lines = md.split(\"\\n\")\n const result: string[] = []\n let inCodeBlock = false\n let codeBlockLang = \"\"\n let codeBlockLines: string[] = []\n let inBlockquote = false\n let tableHeaders: string[] = []\n let inTable = false\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]\n\n // Code block toggle\n if (line.trimStart().startsWith(\"```\")) {\n if (!inCodeBlock) {\n inCodeBlock = true\n codeBlockLang = line.trimStart().slice(3).trim()\n codeBlockLines = []\n continue\n } else {\n inCodeBlock = false\n const code = escapeHtml(codeBlockLines.join(\"\\n\"))\n // Language hint as comment for context\n const langHint = codeBlockLang ? `// ${codeBlockLang}\\n` : \"\"\n result.push(`<pre><code>${langHint}${code}</code></pre>`)\n codeBlockLang = \"\"\n continue\n }\n }\n\n if (inCodeBlock) {\n codeBlockLines.push(line)\n continue\n }\n\n // Close blockquote if we left it\n if (inBlockquote && !line.trimStart().startsWith(\">\")) {\n result.push(\"</blockquote>\")\n inBlockquote = false\n }\n\n // Close table if we left it\n if (inTable && !line.trim().startsWith(\"|\")) {\n inTable = false\n tableHeaders = []\n }\n\n // Blockquote\n if (line.trimStart().startsWith(\"> \")) {\n const content = line.replace(/^>\\s*/, \"\")\n if (!inBlockquote) {\n result.push(\"<blockquote>\")\n inBlockquote = true\n }\n result.push(convertInline(content))\n continue\n }\n\n // Headers → bold with blank line before\n const headerMatch = line.match(/^(#{1,6})\\s+(.+)$/)\n if (headerMatch) {\n result.push(\"\")\n result.push(`<b>${convertInline(headerMatch[2])}</b>`)\n continue\n }\n\n // Horizontal rule\n if (/^[-*_]{3,}\\s*$/.test(line.trim())) {\n result.push(\"———\")\n continue\n }\n\n // Table handling — convert to readable bullet format\n if (line.trim().startsWith(\"|\") && line.trim().endsWith(\"|\")) {\n const cells = line.split(\"|\").slice(1, -1).map(c => c.trim())\n\n // Skip separator rows (|---|---|)\n if (/^\\|[\\s\\-:|]+\\|$/.test(line.trim())) {\n inTable = true\n continue\n }\n\n if (!inTable) {\n // This is the header row\n tableHeaders = cells\n inTable = true\n continue\n }\n\n // Data row — render as bullet with header labels\n if (tableHeaders.length > 0 && cells.length > 0) {\n if (cells.length >= 2) {\n // First cell as bold label, rest as key: value pairs\n const parts: string[] = []\n for (let c = 0; c < cells.length; c++) {\n if (c === 0) {\n parts.push(`<b>${convertInline(cells[c])}</b>`)\n } else {\n const header = tableHeaders[c] ? `${convertInline(tableHeaders[c])}: ` : \"\"\n parts.push(`${header}${convertInline(cells[c])}`)\n }\n }\n result.push(`• ${parts.join(\" — \")}`)\n } else {\n result.push(`• ${convertInline(cells[0])}`)\n }\n }\n continue\n }\n\n // Unordered list\n const ulMatch = line.match(/^(\\s*)[-*+]\\s+(.+)$/)\n if (ulMatch) {\n const indent = ulMatch[1].length > 0 ? \" \" : \"\"\n result.push(`${indent}• ${convertInline(ulMatch[2])}`)\n continue\n }\n\n // Ordered list\n const olMatch = line.match(/^(\\s*)\\d+[.)]\\s+(.+)$/)\n if (olMatch) {\n const indent = olMatch[1].length > 0 ? \" \" : \"\"\n const num = line.match(/^(\\s*)(\\d+)/)?.[2] || \"1\"\n result.push(`${indent}${num}. ${convertInline(olMatch[2])}`)\n continue\n }\n\n // Empty line\n if (!line.trim()) {\n result.push(\"\")\n continue\n }\n\n // Normal text\n result.push(convertInline(line))\n }\n\n // Close unclosed blocks\n if (inCodeBlock) {\n result.push(`<pre><code>${escapeHtml(codeBlockLines.join(\"\\n\"))}</code></pre>`)\n }\n if (inBlockquote) {\n result.push(\"</blockquote>\")\n }\n\n let html = result.join(\"\\n\").trim()\n\n // Wrap file extensions that look like TLDs to prevent Telegram link previews\n // e.g., \"config.ts\" would get wrapped as \"config<code>.ts</code>\"\n html = wrapFileRefsInCode(html)\n\n return html\n}\n\n/**\n * Convert inline markdown to HTML tags.\n */\nfunction convertInline(text: string): string {\n let result = escapeHtml(text)\n\n // Inline code (first, to protect content from further processing)\n result = result.replace(/`([^`]+)`/g, \"<code>$1</code>\")\n\n // Links: [text](url) — must come before bold/italic to preserve URLs\n result = result.replace(\n /\\[([^\\]]+)\\]\\(([^)]+)\\)/g,\n (_m, label, url) => `<a href=\"${escapeHtml(url)}\">${label}</a>`,\n )\n\n // Bold+italic: ***text***\n result = result.replace(/\\*\\*\\*(.+?)\\*\\*\\*/g, \"<b><i>$1</i></b>\")\n\n // Bold: **text**\n result = result.replace(/\\*\\*(.+?)\\*\\*/g, \"<b>$1</b>\")\n\n // Italic: *text* or _text_ (not inside other tags)\n result = result.replace(/(?<!\\*)\\*([^*]+?)\\*(?!\\*)/g, \"<i>$1</i>\")\n\n // Strikethrough: ~~text~~\n result = result.replace(/~~(.+?)~~/g, \"<s>$1</s>\")\n\n // Spoiler: ||text||\n result = result.replace(/\\|\\|(.+?)\\|\\|/g, \"<tg-spoiler>$1</tg-spoiler>\")\n\n return result\n}\n\n/**\n * Wrap file extensions that share TLDs in <code> to prevent Telegram\n * from generating spurious link previews (e.g., config.ts, main.py).\n * Skips content already inside <code>, <pre>, or <a> tags.\n */\nconst FILE_EXT_TLDS = /(?<=\\w)\\.(ts|js|py|rs|go|rb|cs|sh|md|yml|yaml|toml|json|env|css|html|xml|sql|tf|hcl)(?=[\\s,;:)\\]}<]|$)/gi\n\nfunction wrapFileRefsInCode(html: string): string {\n // Split on existing tags to avoid modifying content inside them\n const parts = html.split(/(<\\/?(?:code|pre|a)[^>]*>)/gi)\n let insideTag = false\n\n return parts.map((part) => {\n if (/<(?:code|pre|a)\\b/i.test(part)) {\n insideTag = true\n return part\n }\n if (/<\\/(?:code|pre|a)>/i.test(part)) {\n insideTag = false\n return part\n }\n if (insideTag) return part\n\n return part.replace(FILE_EXT_TLDS, \"<code>.$1</code>\")\n }).join(\"\")\n}\n","import type { ChannelAdapter, IncomingMessage, OutgoingMessage } from \"./types\"\nimport { markdownToTelegramHtml } from \"./telegram-format\"\n\n// --- Telegram Bot API adapter (long-polling, no dependencies) ---\n\ninterface TelegramUpdate {\n update_id: number\n message?: {\n message_id: number\n from: { id: number; first_name: string; last_name?: string; username?: string }\n chat: { id: number; type: string; title?: string }\n text?: string\n caption?: string\n date: number\n reply_to_message?: { message_id: number; text?: string; caption?: string; from?: { first_name: string } }\n photo?: Array<{ file_id: string; file_unique_id: string; width: number; height: number; file_size?: number }>\n voice?: { file_id: string; duration: number; mime_type?: string }\n audio?: { file_id: string; duration: number; mime_type?: string; title?: string }\n video?: { file_id: string; duration: number; mime_type?: string }\n document?: { file_id: string; file_name?: string; mime_type?: string }\n sticker?: { file_id: string; emoji?: string }\n }\n}\n\ninterface TelegramAccountConfig {\n token: string\n agentBinding: string\n}\n\nexport class TelegramAdapter implements ChannelAdapter {\n readonly name = \"telegram\"\n private accounts: Map<string, TelegramAccountConfig>\n private offsets: Map<string, number> = new Map()\n private handler?: (msg: IncomingMessage) => Promise<void>\n private polling = false\n private log: (...args: unknown[]) => void\n\n constructor(\n accounts: Record<string, TelegramAccountConfig>,\n log: (...args: unknown[]) => void = console.error.bind(console, \"[telegram]\"),\n ) {\n this.accounts = new Map(Object.entries(accounts))\n this.log = log\n }\n\n onMessage(handler: (msg: IncomingMessage) => Promise<void>): void {\n this.handler = handler\n }\n\n async start(): Promise<void> {\n this.polling = true\n\n const entries = Array.from(this.accounts.entries())\n this.log(`${entries.length} Telegram account(s) to start`)\n\n for (let i = 0; i < entries.length; i++) {\n const [accountId, config] = entries[i]\n this.log(`Starting polling for account \"${accountId}\" (${i + 1}/${entries.length})`)\n try {\n const me = await this.apiCall(config.token, \"getMe\")\n this.log(`Bot @${me.result?.username} ready (account: ${accountId})`)\n this.pollLoop(accountId, config)\n } catch (e: any) {\n this.log(`Failed to verify bot for account \"${accountId}\": ${e.message}`)\n }\n // Small delay between account starts to avoid Telegram rate limits\n if (i < entries.length - 1) {\n await new Promise((r) => setTimeout(r, 300))\n }\n }\n\n this.log(`All ${entries.length} Telegram account(s) started`)\n }\n\n async stop(): Promise<void> {\n this.polling = false\n }\n\n /**\n * Get token for a specific account ID. Used by router to send from correct bot.\n */\n getTokenForAccount(accountId: string): string | undefined {\n return this.accounts.get(accountId)?.token\n }\n\n /**\n * Get the default (first) account token as fallback.\n */\n private getDefaultToken(): string | undefined {\n const [, config] = Array.from(this.accounts.entries())[0]\n return config?.token\n }\n\n /**\n * Resolve which token to use: prefer accountId, fall back to chatAccountMap, then default.\n */\n private resolveToken(chatId: string, accountId?: string): string | undefined {\n if (accountId) {\n const token = this.getTokenForAccount(accountId)\n if (token) return token\n }\n return this.chatAccountMap.get(chatId)\n ? this.getTokenForAccount(this.chatAccountMap.get(chatId)!)\n : this.getDefaultToken()\n }\n\n /** Track which account a chat was last seen on (for DMs) */\n private chatAccountMap: Map<string, string> = new Map()\n\n /**\n * Send a message. Returns the sent message ID.\n * Pass accountId to send from a specific bot account.\n */\n async send(msg: OutgoingMessage & { accountId?: string }): Promise<string> {\n const token = this.resolveToken(msg.chatId, msg.accountId)\n if (!token) {\n this.log(\"No telegram token found for sending\")\n return \"\"\n }\n\n const maxLen = 4096\n const text = msg.text.length > maxLen ? msg.text.slice(0, maxLen - 3) + \"...\" : msg.text\n\n // Convert markdown to Telegram MarkdownV2\n const formatted = msg.parseMode === \"markdown\" || msg.parseMode === undefined\n ? markdownToTelegramHtml(text)\n : text\n\n const params: Record<string, unknown> = {\n chat_id: msg.chatId,\n text: formatted,\n parse_mode: \"HTML\",\n }\n\n if (msg.replyTo) {\n params.reply_to_message_id = parseInt(msg.replyTo, 10)\n }\n\n if (msg.parseMode === \"html\") {\n params.parse_mode = \"HTML\"\n params.text = text\n } else if (msg.parseMode === \"plain\") {\n delete params.parse_mode\n params.text = text\n }\n\n try {\n const result = await this.apiCall(token, \"sendMessage\", params)\n return String(result.result?.message_id || \"\")\n } catch (e: any) {\n // Retry without formatting if MarkdownV2 fails\n if (params.parse_mode) {\n delete params.parse_mode\n params.text = text\n const result = await this.apiCall(token, \"sendMessage\", params)\n return String(result.result?.message_id || \"\")\n }\n throw e\n }\n }\n\n /**\n * Edit an existing message (for streaming updates).\n */\n async editMessage(chatId: string, messageId: string, text: string, parseMode?: string, accountId?: string): Promise<boolean> {\n const token = this.resolveToken(chatId, accountId)\n if (!token) return false\n\n const maxLen = 4096\n const trimmed = text.length > maxLen ? text.slice(0, maxLen - 3) + \"...\" : text\n\n const formatted = parseMode !== \"html\" && parseMode !== \"plain\"\n ? markdownToTelegramHtml(trimmed)\n : trimmed\n\n const params: Record<string, unknown> = {\n chat_id: chatId,\n message_id: parseInt(messageId, 10),\n text: formatted,\n parse_mode: \"HTML\",\n }\n\n if (parseMode === \"html\") {\n params.parse_mode = \"HTML\"\n params.text = trimmed\n } else if (parseMode === \"plain\") {\n delete params.parse_mode\n params.text = trimmed\n }\n\n try {\n await this.apiCall(token, \"editMessageText\", params)\n return true\n } catch (e: any) {\n if (e.message?.includes(\"message is not modified\")) return true\n if (params.parse_mode) {\n delete params.parse_mode\n params.text = trimmed\n try {\n await this.apiCall(token, \"editMessageText\", params)\n return true\n } catch { return false }\n }\n return false\n }\n }\n\n /**\n * React to a message with an emoji.\n */\n async react(chatId: string, messageId: string, emoji: string = \"👀\", accountId?: string): Promise<void> {\n const token = this.resolveToken(chatId, accountId)\n if (!token) return\n\n try {\n await this.apiCall(token, \"setMessageReaction\", {\n chat_id: chatId,\n message_id: parseInt(messageId, 10),\n reaction: [{ type: \"emoji\", emoji }],\n })\n } catch {\n // Best-effort\n }\n }\n\n /**\n * Send typing indicator.\n */\n async sendTyping(chatId: string, accountId?: string): Promise<void> {\n const token = this.resolveToken(chatId, accountId)\n if (!token) return\n\n try {\n await this.apiCall(token, \"sendChatAction\", {\n chat_id: chatId,\n action: \"typing\",\n })\n } catch {\n // Best-effort\n }\n }\n\n // --- Internal ---\n\n private async pollLoop(accountId: string, config: TelegramAccountConfig): Promise<void> {\n while (this.polling) {\n try {\n const offset = this.offsets.get(accountId) || 0\n const data = await this.apiCall(config.token, \"getUpdates\", {\n offset: offset || undefined,\n timeout: 30,\n allowed_updates: [\"message\"],\n })\n\n const updates: TelegramUpdate[] = data.result || []\n\n for (const update of updates) {\n this.offsets.set(accountId, update.update_id + 1)\n\n if (update.message && this.handler) {\n const msg = update.message\n\n // Extract text from any message type\n let text = msg.text || msg.caption || \"\"\n let mediaInfo: IncomingMessage[\"media\"] | undefined\n\n // Handle media messages\n const hasPhoto = msg.photo && msg.photo.length > 0\n const hasVoice = !!msg.voice\n const hasAudio = !!msg.audio\n const hasVideo = !!msg.video\n const hasDocument = !!msg.document\n const hasMedia = hasPhoto || hasVoice || hasAudio || hasVideo || hasDocument\n\n if (hasMedia) {\n // Download media file\n let fileId: string | undefined\n let mime = \"application/octet-stream\"\n\n if (hasPhoto) {\n fileId = msg.photo![msg.photo!.length - 1].file_id // largest photo\n mime = \"image/jpeg\"\n if (!text) text = \"[Photo attached — please describe what you see]\"\n } else if (hasVoice) {\n fileId = msg.voice!.file_id\n mime = msg.voice!.mime_type || \"audio/ogg\"\n if (!text) text = \"[Voice message — please transcribe and respond]\"\n } else if (hasAudio) {\n fileId = msg.audio!.file_id\n mime = msg.audio!.mime_type || \"audio/mpeg\"\n if (!text) text = `[Audio: ${msg.audio!.title || \"audio file\"}]`\n } else if (hasVideo) {\n fileId = msg.video!.file_id\n mime = msg.video!.mime_type || \"video/mp4\"\n if (!text) text = \"[Video attached]\"\n } else if (hasDocument) {\n fileId = msg.document!.file_id\n mime = msg.document!.mime_type || \"application/octet-stream\"\n if (!text) text = `[Document: ${msg.document!.file_name || \"file\"}]`\n }\n\n if (fileId) {\n try {\n // Get file path from Telegram\n const fileInfo = await this.apiCall(config.token, \"getFile\", { file_id: fileId })\n const filePath = fileInfo.result?.file_path\n if (filePath) {\n // Download file\n const fileUrl = `https://api.telegram.org/file/bot${config.token}/${filePath}`\n const res = await fetch(fileUrl)\n if (res.ok) {\n const buffer = Buffer.from(await res.arrayBuffer())\n const ext = mime.split(\"/\")[1]?.split(\";\")[0] || \"bin\"\n const { mkdirSync, writeFileSync } = await import(\"fs\")\n const { randomUUID } = await import(\"crypto\")\n const { resolve, join } = await import(\"path\")\n const mediaDir = resolve(process.cwd(), \".agentx/media/telegram\")\n mkdirSync(mediaDir, { recursive: true })\n const fileName = msg.document?.file_name || `${randomUUID()}.${ext}`\n const localPath = join(mediaDir, fileName)\n writeFileSync(localPath, buffer)\n mediaInfo = { path: localPath, type: mime, fileName }\n }\n }\n } catch (e: any) {\n this.log(`Media download failed: ${e.message}`)\n }\n }\n }\n\n if (!text) continue\n\n const incoming: IncomingMessage = {\n id: String(msg.message_id),\n channel: \"telegram\",\n accountId,\n sender: {\n id: String(msg.from.id),\n name: [msg.from.first_name, msg.from.last_name].filter(Boolean).join(\" \"),\n username: msg.from.username,\n },\n group: msg.chat.type !== \"private\"\n ? { id: String(msg.chat.id), name: msg.chat.title || \"\" }\n : undefined,\n text,\n media: mediaInfo,\n replyTo: msg.reply_to_message\n ? String(msg.reply_to_message.message_id)\n : undefined,\n replyToText: msg.reply_to_message\n ? (msg.reply_to_message.text || msg.reply_to_message.caption || `[message from ${msg.reply_to_message.from?.first_name || \"unknown\"}]`)\n : undefined,\n timestamp: new Date(msg.date * 1000),\n raw: update,\n }\n\n // Track chat→account mapping for DM replies\n this.chatAccountMap.set(String(msg.chat.id), accountId)\n\n this.handler(incoming).catch((e) => {\n this.log(`Error handling message: ${e.message}`)\n })\n }\n }\n } catch (e: any) {\n this.log(`Poll error (${accountId}): ${e.message}`)\n await new Promise((r) => setTimeout(r, 5000))\n }\n }\n }\n\n private async apiCall(\n token: string,\n method: string,\n params?: Record<string, unknown>,\n ): Promise<any> {\n const url = `https://api.telegram.org/bot${token}/${method}`\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: params ? JSON.stringify(params) : undefined,\n })\n\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`Telegram API error: ${res.status} ${text}`)\n }\n\n return res.json()\n }\n}\n","import type { ChannelAdapter, IncomingMessage, OutgoingMessage } from \"./types\"\nimport { existsSync, mkdirSync, writeFileSync } from \"fs\"\nimport { resolve, join } from \"path\"\nimport { randomUUID } from \"crypto\"\n\n// --- WhatsApp adapter using Baileys (WhatsApp Web multi-device) ---\n// Baileys is an optional dependency. If not installed, adapter logs a warning.\n//\n// First run: displays QR code in terminal for pairing.\n// Subsequent runs: reconnects automatically using saved session.\n\nexport interface WhatsAppRoute {\n contact?: string // phone number or partial match\n group?: string // group name or JID partial match\n agent: string // agent ID to route to\n}\n\nexport class WhatsAppAdapter implements ChannelAdapter {\n readonly name = \"whatsapp\"\n private sessionDir: string\n private defaultAgent?: string\n private allowFrom?: string[]\n private routes: WhatsAppRoute[]\n private handler?: (msg: IncomingMessage) => Promise<void>\n private sock: any = null\n private sentMessageIds: Set<string> = new Set() // Track our own replies to prevent loops\n private log: (...args: unknown[]) => void\n\n constructor(\n config: {\n sessionDir: string\n defaultAgent?: string\n allowFrom?: string[]\n routes?: WhatsAppRoute[]\n },\n log: (...args: unknown[]) => void = console.error.bind(console, \"[whatsapp]\"),\n ) {\n this.sessionDir = resolve(config.sessionDir)\n this.defaultAgent = config.defaultAgent\n this.allowFrom = config.allowFrom\n this.routes = config.routes || []\n this.log = log\n }\n\n /**\n * Resolve which agent handles a message based on routes.\n */\n resolveAgent(senderPhone: string, groupName?: string, groupJid?: string): string | undefined {\n for (const route of this.routes) {\n // Match by contact phone number\n if (route.contact) {\n const normalized = route.contact.replace(/\\+/g, \"\")\n if (senderPhone.includes(normalized) || normalized.includes(senderPhone)) {\n return route.agent\n }\n }\n // Match by group name or JID\n if (route.group && (groupName || groupJid)) {\n const pattern = route.group.toLowerCase()\n if (\n groupName?.toLowerCase().includes(pattern) ||\n groupJid?.toLowerCase().includes(pattern)\n ) {\n return route.agent\n }\n }\n }\n return this.defaultAgent\n }\n\n onMessage(handler: (msg: IncomingMessage) => Promise<void>): void {\n this.handler = handler\n }\n\n async start(): Promise<void> {\n // Dynamic import — Baileys is optional\n let makeWASocket: any\n let useMultiFileAuthState: any\n let DisconnectReason: any\n\n let baileys: any\n try {\n baileys = await import(\"@whiskeysockets/baileys\")\n makeWASocket = baileys.default || baileys.makeWASocket\n useMultiFileAuthState = baileys.useMultiFileAuthState\n DisconnectReason = baileys.DisconnectReason\n } catch {\n this.log(\"WhatsApp requires @whiskeysockets/baileys. Install with:\")\n this.log(\" npm install @whiskeysockets/baileys\")\n return\n }\n\n mkdirSync(this.sessionDir, { recursive: true })\n\n const { state, saveCreds } = await useMultiFileAuthState(this.sessionDir)\n\n // Fetch latest WhatsApp Web version (critical for avoiding 405 errors)\n let version: [number, number, number] | undefined\n try {\n const { version: v } = await baileys.fetchLatestBaileysVersion()\n version = v\n this.log(`WhatsApp Web version: ${v.join(\".\")}`)\n } catch {\n this.log(\"Could not fetch WA version, using default\")\n }\n\n // Silent logger with proper method stubs (Baileys v7 requires all methods)\n const silentLogger = {\n level: \"silent\",\n trace: () => {}, debug: () => {}, info: () => {},\n warn: () => {}, fatal: () => {},\n error: (...args: any[]) => this.log(\"WA error:\", ...args),\n child: () => silentLogger,\n } as any\n\n this.sock = makeWASocket({\n auth: {\n creds: state.creds,\n keys: baileys.makeCacheableSignalKeyStore\n ? baileys.makeCacheableSignalKeyStore(state.keys, silentLogger)\n : state.keys,\n },\n ...(version ? { version } : {}),\n logger: silentLogger,\n printQRInTerminal: false,\n browser: [\"agentx\", \"server\", \"1.0\"],\n syncFullHistory: false,\n markOnlineOnConnect: false,\n })\n\n // Save credentials on update\n this.sock.ev.on(\"creds.update\", saveCreds)\n\n // Debug: log all events to diagnose message reception\n this.sock.ev.on(\"messaging-history.set\", (data: any) => {\n this.log(`WA history sync: ${data.messages?.length || 0} messages, ${data.isLatest ? \"latest\" : \"partial\"}`)\n })\n\n // Handle connection updates\n this.sock.ev.on(\"connection.update\", async (update: any) => {\n const { connection, lastDisconnect, qr } = update\n\n if (qr) {\n this.log(\"Scan QR code with WhatsApp to connect:\")\n // Render QR as text in terminal\n try {\n // @ts-ignore - no type declarations for qrcode-terminal\n const { default: qrcode } = await import(\"qrcode-terminal\") as any\n qrcode.generate(qr, { small: true })\n } catch {\n // If qrcode-terminal not available, log raw QR string\n this.log(`QR: ${qr}`)\n this.log(\"Install qrcode-terminal for visual QR: npm install qrcode-terminal\")\n }\n }\n\n if (connection === \"close\") {\n const statusCode = lastDisconnect?.error?.output?.statusCode\n this.log(`WhatsApp connection closed (status: ${statusCode})`)\n\n if (statusCode === 515) {\n // Stream error — restart after delay\n this.log(\"Stream error, reconnecting in 5s...\")\n setTimeout(() => this.start(), 5000)\n } else if (statusCode === DisconnectReason?.loggedOut || statusCode === 401) {\n this.log(\"Logged out. Delete session dir and restart to re-scan QR.\")\n } else if (statusCode !== undefined) {\n this.log(\"Reconnecting in 3s...\")\n setTimeout(() => this.start(), 3000)\n }\n // If statusCode is undefined, don't reconnect (likely startup failure)\n }\n\n if (connection === \"open\") {\n this.log(\"WhatsApp connected\")\n }\n })\n\n // Handle incoming messages\n this.sock.ev.on(\"messages.upsert\", async (m: any) => {\n this.log(`WA messages.upsert: ${m.messages?.length || 0} messages, type: ${m.type}`)\n\n if (!this.handler) return\n\n for (const msg of m.messages || []) {\n const jidShort = (msg.key.remoteJid || \"\").replace(/@.*/, \"\").slice(-6)\n const hasText = !!(msg.message?.conversation || msg.message?.extendedTextMessage?.text)\n this.log(`WA msg: from=${jidShort} fromMe=${msg.key.fromMe} hasText=${hasText} type=${Object.keys(msg.message || {}).join(\",\")}`)\n\n // Skip status broadcasts\n if (msg.key.remoteJid === \"status@broadcast\") continue\n\n // Skip messages we sent as replies (prevents loops)\n if (msg.key.id && this.sentMessageIds.has(msg.key.id)) {\n this.sentMessageIds.delete(msg.key.id)\n continue\n }\n\n // For fromMe: only process self-chat (messaging yourself = talking to agent)\n // OpenClaw pattern: if your own number is in allowFrom, self-chat is enabled.\n // WhatsApp uses LID format for self-chat remoteJid.\n if (msg.key.fromMe) {\n const me = this.sock?.user\n const remoteJid = msg.key.remoteJid || \"\"\n // Self-chat: remoteJid matches our JID or LID\n const myJid = me?.id?.replace(/:.*/, \"\") || \"\" // 21624309128\n const myLid = me?.lid?.replace(/:.*/, \"\") || \"\" // 214997540012179\n const chatUser = remoteJid.replace(/:.*/, \"\").replace(/@.*/, \"\")\n const isSelfChat = (chatUser === myJid) || (chatUser === myLid)\n if (!isSelfChat) continue\n }\n\n // Extract text content + detect media\n let text = msg.message?.conversation\n || msg.message?.extendedTextMessage?.text\n || msg.message?.imageMessage?.caption\n || msg.message?.videoMessage?.caption\n || \"\"\n\n // Detect media type\n const msgContent = msg.message || {}\n const hasImage = !!msgContent.imageMessage\n const hasAudio = !!msgContent.audioMessage\n const hasVideo = !!msgContent.videoMessage\n const hasDocument = !!msgContent.documentMessage\n const hasSticker = !!msgContent.stickerMessage\n const hasMedia = hasImage || hasAudio || hasVideo || hasDocument || hasSticker\n\n // Add media placeholder to text if no caption\n if (hasMedia && !text) {\n if (hasImage) text = \"[Image attached — please describe what you see]\"\n else if (hasAudio) text = \"[Voice message attached — please transcribe and respond]\"\n else if (hasVideo) text = \"[Video attached]\"\n else if (hasDocument) text = `[Document: ${msgContent.documentMessage?.fileName || \"file\"}]`\n else if (hasSticker) text = \"[Sticker]\"\n }\n\n if (!text) continue\n\n const jid = msg.key.remoteJid || \"\"\n const isGroup = jid.endsWith(\"@g.us\")\n\n // For DMs: remoteJid is the conversation partner\n // For groups: participant is the sender\n const chatPhone = jid.replace(/@.*$/, \"\")\n const senderJid = isGroup ? (msg.key.participant || \"\") : jid\n const senderPhone = senderJid.replace(/@.*$/, \"\")\n\n // Allowlist check — match against chat (conversation partner) not just sender\n // This allows the owner (fromMe) to talk to their agent via any contact\n if (this.allowFrom?.length && !msg.key.fromMe) {\n const allowed = this.allowFrom.some(p => {\n const normalized = p.replace(/\\+/g, \"\")\n return senderPhone.includes(normalized) || chatPhone.includes(normalized)\n })\n if (!allowed) continue\n }\n\n const senderName = msg.key.fromMe ? \"me\" : (msg.pushName || senderPhone)\n\n // Get group name if available\n let groupName: string | undefined\n if (isGroup && this.sock) {\n try {\n const metadata = await this.sock.groupMetadata(jid)\n groupName = metadata.subject\n } catch { /* group metadata unavailable */ }\n }\n\n // Route to agent based on contact/group rules\n const resolvedAgent = this.resolveAgent(senderPhone, groupName, isGroup ? jid : undefined)\n if (!resolvedAgent) {\n this.log(`No route for ${isGroup ? `group ${groupName || jid}` : senderPhone}, skipping`)\n continue\n }\n\n // Download and save media if present\n let mediaInfo: IncomingMessage[\"media\"] | undefined\n if (hasMedia && this.sock) {\n try {\n const baileys = await import(\"@whiskeysockets/baileys\")\n const buffer = await baileys.downloadMediaMessage(msg, \"buffer\", {}, {\n reuploadRequest: this.sock.updateMediaMessage,\n logger: this.sock.logger,\n })\n if (buffer) {\n const mime = msgContent.imageMessage?.mimetype\n || msgContent.audioMessage?.mimetype || \"audio/ogg\"\n || msgContent.videoMessage?.mimetype || \"video/mp4\"\n || msgContent.documentMessage?.mimetype\n || msgContent.stickerMessage?.mimetype || \"image/webp\"\n || \"application/octet-stream\"\n const ext = mime.split(\"/\")[1]?.split(\";\")[0] || \"bin\"\n const mediaDir = resolve(this.sessionDir, \"../media/inbound\")\n mkdirSync(mediaDir, { recursive: true })\n const fileName = msgContent.documentMessage?.fileName || `${randomUUID()}.${ext}`\n const filePath = join(mediaDir, fileName)\n writeFileSync(filePath, buffer)\n mediaInfo = { path: filePath, type: mime, fileName }\n this.log(`WA media saved: ${mime} -> ${filePath}`)\n }\n } catch (e: any) {\n this.log(`WA media download failed: ${e.message}`)\n }\n }\n\n const incoming: IncomingMessage = {\n id: msg.key.id || String(Date.now()),\n channel: \"whatsapp\",\n accountId: \"default\",\n sender: {\n id: msg.key.fromMe\n ? (this.sock?.user?.id?.replace(/:.*/, \"\") || senderPhone) + \"@s.whatsapp.net\"\n : senderPhone,\n name: senderName,\n username: senderPhone,\n },\n group: isGroup ? {\n id: jid,\n name: groupName || jid,\n } : undefined,\n text,\n media: mediaInfo,\n replyTo: msg.message?.extendedTextMessage?.contextInfo?.stanzaId,\n timestamp: new Date((msg.messageTimestamp || 0) * 1000),\n raw: msg,\n resolvedAgent,\n }\n\n this.handler(incoming).catch((e: any) => {\n this.log(`Error handling message: ${e.message}`)\n })\n }\n })\n }\n\n async stop(): Promise<void> {\n if (this.sock) {\n this.sock.end()\n this.sock = null\n }\n }\n\n async send(msg: OutgoingMessage): Promise<string> {\n if (!this.sock) {\n this.log(\"WhatsApp not connected\")\n return \"\"\n }\n\n const jid = msg.chatId.includes(\"@\")\n ? msg.chatId\n : `${msg.chatId}@s.whatsapp.net`\n\n try {\n const sent = await this.sock.sendMessage(jid, { text: msg.text })\n const sentId = sent?.key?.id || \"\"\n // Track to prevent loop (our own reply echoed back as fromMe)\n if (sentId) this.sentMessageIds.add(sentId)\n return sentId\n } catch (e: any) {\n this.log(`Send error: ${e.message}`)\n return \"\"\n }\n }\n\n async editMessage(chatId: string, messageId: string, text: string): Promise<boolean> {\n if (!this.sock) return false\n const jid = chatId.includes(\"@\") ? chatId : `${chatId}@s.whatsapp.net`\n try {\n await this.sock.sendMessage(jid, {\n text,\n edit: { remoteJid: jid, id: messageId, fromMe: true },\n })\n return true\n } catch { return false }\n }\n\n async sendTyping(chatId: string): Promise<void> {\n if (!this.sock) return\n const jid = chatId.includes(\"@\") ? chatId : `${chatId}@s.whatsapp.net`\n try {\n await this.sock.sendPresenceUpdate(\"composing\", jid)\n } catch { /* best-effort */ }\n }\n\n async react(chatId: string, messageId: string, emoji: string = \"👀\"): Promise<void> {\n if (!this.sock) return\n const jid = chatId.includes(\"@\") ? chatId : `${chatId}@s.whatsapp.net`\n try {\n await this.sock.sendMessage(jid, {\n react: { text: emoji, key: { remoteJid: jid, id: messageId } },\n })\n } catch { /* best-effort */ }\n }\n}\n","import type { DaemonConfig, CronJobDef } from \"@/daemon/config\"\nimport type { AgentRegistry } from \"@/agents/registry\"\nimport type { HookRegistry } from \"@/hooks\"\nimport type { CronJobState, CronRunResult } from \"./types\"\nimport { writeFileSync, mkdirSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\n\n// --- Cron Scheduler: lightweight cron engine with timezone support ---\n// No external dependencies — uses setTimeout-based scheduling.\n\n/**\n * Parse a cron expression into next-fire timestamp.\n * Supports standard 5-field format: minute hour day-of-month month day-of-week\n */\nfunction parseCronField(field: string, min: number, max: number): number[] {\n const values: number[] = []\n\n for (const part of field.split(\",\")) {\n if (part === \"*\") {\n for (let i = min; i <= max; i++) values.push(i)\n } else if (part.includes(\"/\")) {\n const [range, stepStr] = part.split(\"/\")\n const step = parseInt(stepStr, 10)\n const start = range === \"*\" ? min : parseInt(range, 10)\n for (let i = start; i <= max; i += step) values.push(i)\n } else if (part.includes(\"-\")) {\n const [a, b] = part.split(\"-\").map(Number)\n for (let i = a; i <= b; i++) values.push(i)\n } else {\n values.push(parseInt(part, 10))\n }\n }\n\n return [...new Set(values)].sort((a, b) => a - b)\n}\n\nfunction getNextCronDate(expression: string, after: Date, timezone: string): Date {\n const fields = expression.trim().split(/\\s+/)\n if (fields.length !== 5) throw new Error(`Invalid cron: ${expression}`)\n\n const minutes = parseCronField(fields[0], 0, 59)\n const hours = parseCronField(fields[1], 0, 23)\n const daysOfMonth = parseCronField(fields[2], 1, 31)\n const months = parseCronField(fields[3], 1, 12)\n const daysOfWeek = parseCronField(fields[4], 0, 6)\n\n // Convert to timezone-aware date\n const fmt = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: timezone,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n })\n\n // Start searching from next minute\n const candidate = new Date(after.getTime() + 60_000)\n candidate.setSeconds(0, 0)\n\n // Search up to 1 year ahead\n const limit = new Date(candidate.getTime() + 366 * 24 * 60 * 60 * 1000)\n\n while (candidate < limit) {\n const parts = fmt.formatToParts(candidate)\n const get = (type: string) => parseInt(parts.find((p) => p.type === type)?.value || \"0\", 10)\n\n const m = get(\"minute\")\n const h = get(\"hour\")\n const dom = get(\"day\")\n const mon = get(\"month\")\n const dow = candidate.getDay()\n\n if (\n minutes.includes(m) &&\n hours.includes(h) &&\n daysOfMonth.includes(dom) &&\n months.includes(mon) &&\n daysOfWeek.includes(dow)\n ) {\n return candidate\n }\n\n // Advance by 1 minute\n candidate.setTime(candidate.getTime() + 60_000)\n }\n\n throw new Error(`No next run found for cron \"${expression}\" within 1 year`)\n}\n\nexport class CronScheduler {\n private jobs: Map<string, CronJobState> = new Map()\n private timers: Map<string, ReturnType<typeof setTimeout>> = new Map()\n private registry: AgentRegistry\n private hooks?: HookRegistry\n private runsDir: string\n private running = false\n private log: (...args: unknown[]) => void\n\n constructor(\n config: DaemonConfig,\n registry: AgentRegistry,\n hooks?: HookRegistry,\n log: (...args: unknown[]) => void = console.error.bind(console, \"[cron]\"),\n ) {\n this.registry = registry\n this.hooks = hooks\n this.log = log\n this.runsDir = resolve(process.cwd(), \".agentx/cron/runs\")\n\n for (const [id, def] of Object.entries(config.crons)) {\n this.jobs.set(id, {\n id,\n enabled: def.enabled,\n schedule: def.schedule,\n timezone: def.timezone,\n agent: def.agent,\n prompt: def.prompt,\n timeout: def.timeout,\n model: def.model,\n onError: def.onError,\n consecutiveErrors: 0,\n totalRuns: 0,\n })\n }\n }\n\n async start(): Promise<void> {\n this.running = true\n\n if (!existsSync(this.runsDir)) {\n mkdirSync(this.runsDir, { recursive: true })\n }\n\n for (const [id, job] of this.jobs) {\n if (!job.enabled) {\n this.log(`Job \"${id}\" is disabled, skipping`)\n continue\n }\n this.scheduleNext(id)\n }\n\n this.log(`${this.jobs.size} cron job(s) loaded, ${Array.from(this.jobs.values()).filter((j) => j.enabled).length} enabled`)\n }\n\n async stop(): Promise<void> {\n this.running = false\n for (const timer of this.timers.values()) {\n clearTimeout(timer)\n }\n this.timers.clear()\n }\n\n private scheduleNext(jobId: string): void {\n const job = this.jobs.get(jobId)\n if (!job || !job.enabled || !this.running) return\n\n try {\n const nextRun = getNextCronDate(job.schedule, new Date(), job.timezone)\n job.nextRun = nextRun\n const delay = nextRun.getTime() - Date.now()\n\n this.log(`Job \"${jobId}\" next run: ${nextRun.toISOString()} (in ${Math.round(delay / 1000)}s)`)\n\n const timer = setTimeout(() => this.executeJob(jobId), delay)\n this.timers.set(jobId, timer)\n } catch (e: any) {\n this.log(`Failed to schedule \"${jobId}\": ${e.message}`)\n }\n }\n\n private async executeJob(jobId: string): Promise<void> {\n const job = this.jobs.get(jobId)\n if (!job || !this.running) return\n\n // Pre-hook\n if (this.hooks?.has(\"pre:cron-run\" as any)) {\n const hookResult = await this.hooks.execute(\"pre:cron-run\" as any, {\n event: \"pre:cron-run\" as any,\n jobId,\n agent: job.agent,\n prompt: job.prompt,\n })\n if (hookResult.blocked) {\n this.log(`Job \"${jobId}\" blocked by hook: ${hookResult.message}`)\n this.scheduleNext(jobId)\n return\n }\n }\n\n this.log(`Executing job \"${jobId}\" -> agent \"${job.agent}\"`)\n const startedAt = new Date()\n job.lastRun = startedAt\n job.totalRuns++\n\n try {\n const response = await this.registry.execute({\n message: job.prompt,\n agentId: job.agent,\n context: { channel: \"cron\" },\n })\n\n const result: CronRunResult = {\n jobId,\n startedAt,\n completedAt: new Date(),\n success: !response.error,\n response: response.content,\n error: response.error,\n duration: response.duration || Date.now() - startedAt.getTime(),\n }\n\n if (response.error) {\n job.consecutiveErrors++\n this.log(`Job \"${jobId}\" failed (${job.consecutiveErrors} consecutive): ${response.error}`)\n\n if (job.onError === \"disable\" && job.consecutiveErrors >= 3) {\n job.enabled = false\n this.log(`Job \"${jobId}\" disabled after ${job.consecutiveErrors} consecutive errors`)\n }\n } else {\n job.consecutiveErrors = 0\n this.log(`Job \"${jobId}\" completed in ${result.duration}ms`)\n }\n\n // Log run\n this.logRun(result)\n\n // Post-hook\n if (this.hooks?.has(\"post:cron-run\" as any)) {\n await this.hooks.execute(\"post:cron-run\" as any, {\n event: \"post:cron-run\" as any,\n jobId,\n success: result.success,\n duration: result.duration,\n error: result.error ? new Error(result.error) : undefined,\n })\n }\n } catch (e: any) {\n job.consecutiveErrors++\n this.log(`Job \"${jobId}\" threw: ${e.message}`)\n }\n\n // Schedule next run\n this.scheduleNext(jobId)\n }\n\n private logRun(result: CronRunResult): void {\n try {\n const runDir = resolve(this.runsDir, result.jobId)\n if (!existsSync(runDir)) {\n mkdirSync(runDir, { recursive: true })\n }\n\n const filename = `${result.startedAt.toISOString().replace(/[:.]/g, \"-\")}.json`\n writeFileSync(\n resolve(runDir, filename),\n JSON.stringify(result, null, 2),\n )\n } catch {\n // Don't fail on logging errors\n }\n }\n\n /**\n * List all jobs and their status.\n */\n list(): CronJobState[] {\n return Array.from(this.jobs.values())\n }\n}\n","import { createServer, type IncomingMessage, type ServerResponse } from \"http\"\nimport { loadDaemonConfig, validateWorkspaces, type DaemonConfig } from \"./config\"\nimport { AgentRegistry } from \"@/agents/registry\"\nimport { MessageRouter } from \"@/channels/router\"\nimport { TelegramAdapter } from \"@/channels/telegram\"\nimport { WhatsAppAdapter } from \"@/channels/whatsapp\"\nimport { DiscordAdapter } from \"@/channels/discord\"\nimport { CronScheduler } from \"@/crons/scheduler\"\nimport { A2AMesh } from \"@/a2a/mesh\"\nimport { HookRegistry, loadHooks } from \"@/hooks\"\n\n// --- AgentX Daemon: the thin orchestration layer ---\n//\n// This is NOT an AI runtime. It's a message router + scheduler + mesh\n// that triggers Claude Code sessions in workspace directories.\n//\n// Each agent = a workspace with .claude/ config\n// agentx just orchestrates WHEN and WHERE Claude Code runs.\n\nexport class AgentXDaemon {\n private config: DaemonConfig\n private registry: AgentRegistry\n private router: MessageRouter\n private cron: CronScheduler\n private mesh?: A2AMesh\n private hooks: HookRegistry\n private httpServer?: ReturnType<typeof createServer>\n private log: (...args: unknown[]) => void\n\n constructor(configPath?: string) {\n this.log = console.error.bind(console, \"[agentx]\")\n\n // Load config\n this.log(\"Loading configuration...\")\n this.config = loadDaemonConfig(configPath)\n\n // Validate\n const warnings = validateWorkspaces(this.config)\n for (const w of warnings) {\n this.log(` ⚠ ${w}`)\n }\n\n // Initialize hooks\n this.hooks = new HookRegistry()\n loadHooks(process.cwd(), this.hooks)\n\n // Initialize agent registry\n this.registry = new AgentRegistry(this.config, this.log)\n\n // Initialize message router\n this.router = new MessageRouter(this.registry, this.config, this.hooks, this.log)\n\n // Initialize cron scheduler\n this.cron = new CronScheduler(this.config, this.registry, this.hooks, this.log)\n\n // Initialize mesh (if enabled)\n if (this.config.mesh.enabled) {\n this.mesh = new A2AMesh(this.config, this.log)\n this.router.setMesh(this.mesh)\n }\n }\n\n async start(): Promise<void> {\n this.log(\"\")\n this.log(\" ┌─────────────────────────────────────┐\")\n this.log(\" │ agentx daemon │\")\n this.log(\" └─────────────────────────────────────┘\")\n this.log(\"\")\n this.log(` Node: ${this.config.node.name} (${this.config.node.id})`)\n this.log(` Bind: ${this.config.node.bind}`)\n this.log(\"\")\n\n // 1. Start channels\n await this.startChannels()\n\n // 2. Start cron scheduler\n await this.cron.start()\n\n // 3. Start mesh\n if (this.mesh) {\n await this.mesh.start()\n }\n\n // 4. Start HTTP API\n await this.startHttpApi()\n\n // Print agent summary\n this.log(\"\")\n this.log(\" Agents:\")\n for (const agent of this.registry.list()) {\n this.log(` ${agent.id} (${agent.tier}) → ${agent.workspace}`)\n }\n\n // Print cron summary\n const cronJobs = this.cron.list()\n if (cronJobs.length) {\n this.log(\"\")\n this.log(\" Cron Jobs:\")\n for (const job of cronJobs) {\n const status = job.enabled ? \"enabled\" : \"disabled\"\n this.log(` ${job.id} [${status}] → ${job.agent} (${job.schedule})`)\n }\n }\n\n // Print mesh summary\n if (this.mesh) {\n this.log(\"\")\n this.log(\" Mesh Peers:\")\n for (const peer of this.mesh.directory()) {\n const status = peer.healthy ? \"✓\" : \"✗\"\n this.log(` ${status} ${peer.peer} (${peer.peerUrl})`)\n }\n }\n\n this.log(\"\")\n this.log(\" Ready.\")\n this.log(\"\")\n\n // Graceful shutdown\n process.on(\"SIGINT\", () => this.stop())\n process.on(\"SIGTERM\", () => this.stop())\n }\n\n async stop(): Promise<void> {\n this.log(\"Shutting down...\")\n await this.router.stopAll()\n await this.cron.stop()\n if (this.mesh) await this.mesh.stop()\n if (this.httpServer) {\n this.httpServer.close()\n }\n this.log(\"Goodbye.\")\n process.exit(0)\n }\n\n private async startChannels(): Promise<void> {\n // Telegram\n if (this.config.channels.telegram.enabled) {\n const accounts = this.config.channels.telegram.accounts\n if (Object.keys(accounts).length > 0) {\n const telegram = new TelegramAdapter(accounts, this.log)\n this.router.addChannel(telegram)\n this.log(\" Telegram: enabled\")\n }\n }\n\n // WhatsApp\n if (this.config.channels.whatsapp.enabled) {\n const whatsapp = new WhatsAppAdapter(\n {\n sessionDir: this.config.channels.whatsapp.sessionDir,\n defaultAgent: this.config.channels.whatsapp.defaultAgent,\n allowFrom: this.config.channels.whatsapp.allowFrom,\n routes: this.config.channels.whatsapp.routes,\n },\n this.log,\n )\n this.router.addChannel(whatsapp)\n this.log(` WhatsApp: enabled (${this.config.channels.whatsapp.routes.length} routes)`)\n }\n\n // Discord\n if (this.config.channels.discord?.enabled && this.config.channels.discord.token) {\n const discord = new DiscordAdapter(\n {\n token: this.config.channels.discord.token,\n agentBinding: this.config.channels.discord.agentBinding,\n },\n this.log,\n )\n this.router.addChannel(discord)\n this.log(\" Discord: enabled\")\n }\n\n await this.router.startAll()\n }\n\n private async startHttpApi(): Promise<void> {\n const [host, portStr] = this.config.node.bind.split(\":\")\n const port = parseInt(portStr || \"18800\", 10)\n\n this.httpServer = createServer(async (req, res) => {\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\")\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, OPTIONS\")\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization\")\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204)\n res.end()\n return\n }\n\n await this.handleHttp(req, res)\n })\n\n this.httpServer.on(\"error\", (err: any) => {\n if (err.code === \"EADDRINUSE\") {\n this.log(` ERROR: Port ${port} is already in use. Retrying in 5s...`)\n setTimeout(() => {\n this.httpServer?.close()\n this.httpServer?.listen(port, host || \"0.0.0.0\")\n }, 5000)\n } else {\n this.log(` HTTP error: ${err.message}`)\n }\n })\n\n this.httpServer.listen(port, host || \"0.0.0.0\", () => {\n this.log(` HTTP API: http://${host || \"0.0.0.0\"}:${port}`)\n })\n }\n\n private async handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const url = new URL(req.url || \"/\", `http://${req.headers.host || \"localhost\"}`)\n const path = url.pathname\n\n try {\n switch (`${req.method} ${path}`) {\n case \"GET /health\":\n this.json(res, 200, {\n status: \"ok\",\n node: this.config.node,\n uptime: process.uptime(),\n agents: this.registry.list(),\n crons: this.cron.list().map((j) => ({ id: j.id, enabled: j.enabled, nextRun: j.nextRun })),\n mesh: this.mesh?.directory() || [],\n })\n break\n\n case \"GET /agents\":\n this.json(res, 200, this.registry.list())\n break\n\n case \"GET /crons\":\n this.json(res, 200, this.cron.list())\n break\n\n case \"GET /mesh\":\n this.json(res, 200, this.mesh?.directory() || [])\n break\n\n case \"POST /task\": {\n const body = await readBody(req)\n if (!body.agent || !body.message) {\n this.json(res, 400, { error: \"Missing: agent, message\" })\n return\n }\n const response = await this.registry.execute({\n agentId: body.agent as string,\n message: body.message as string,\n context: body.context as any,\n })\n this.json(res, response.error ? 500 : 200, response)\n break\n }\n\n case \"POST /mesh/task\": {\n const body = await readBody(req)\n if (!body.peer || !body.message) {\n this.json(res, 400, { error: \"Missing: peer, message\" })\n return\n }\n if (!this.mesh) {\n this.json(res, 400, { error: \"Mesh not enabled\" })\n return\n }\n const result = await this.mesh.sendTask(body.peer as string, body.message as string)\n this.json(res, 200, { response: result })\n break\n }\n\n // A2A agent card discovery\n case \"GET /.well-known/agent-card.json\":\n this.json(res, 200, {\n name: this.config.node.name,\n description: `AgentX daemon node \"${this.config.node.name}\"`,\n url: `http://${this.config.node.bind}`,\n version: \"1.0.0\",\n capabilities: {\n streaming: false,\n pushNotifications: false,\n stateTransitionHistory: false,\n },\n skills: this.registry.list().map((a) => ({\n id: a.id,\n name: a.name,\n description: `Agent \"${a.name}\" (${a.tier})`,\n tags: [a.tier],\n })),\n defaultInputModes: [\"text\"],\n defaultOutputModes: [\"text\"],\n })\n break\n\n default:\n this.json(res, 404, {\n error: \"Not found\",\n endpoints: [\n \"GET /health\",\n \"GET /agents\",\n \"GET /crons\",\n \"GET /mesh\",\n \"POST /task { agent, message, context? }\",\n \"POST /mesh/task { peer, message }\",\n \"GET /.well-known/agent-card.json\",\n ],\n })\n }\n } catch (e: any) {\n this.json(res, 500, { error: e.message })\n }\n }\n\n private json(res: ServerResponse, status: number, data: unknown): void {\n res.writeHead(status, { \"Content-Type\": \"application/json\" })\n res.end(JSON.stringify(data, null, 2))\n }\n}\n\nasync function readBody(req: IncomingMessage): Promise<Record<string, unknown>> {\n return new Promise((resolve, reject) => {\n let body = \"\"\n req.on(\"data\", (chunk: Buffer) => (body += chunk.toString()))\n req.on(\"end\", () => {\n try {\n resolve(body ? JSON.parse(body) : {})\n } catch {\n resolve({})\n }\n })\n req.on(\"error\", reject)\n })\n}\n","import type { ChannelAdapter, IncomingMessage, OutgoingMessage } from \"./types\"\n\n// --- Discord adapter using discord.js ---\n// discord.js is an optional dependency.\n// Bot needs MESSAGE_CONTENT intent enabled in Discord Developer Portal.\n\nexport class DiscordAdapter implements ChannelAdapter {\n readonly name = \"discord\"\n private token: string\n private agentBinding?: string\n private handler?: (msg: IncomingMessage) => Promise<void>\n private client: any = null\n private log: (...args: unknown[]) => void\n\n constructor(\n config: { token: string; agentBinding?: string },\n log: (...args: unknown[]) => void = console.error.bind(console, \"[discord]\"),\n ) {\n this.token = config.token\n this.agentBinding = config.agentBinding\n this.log = log\n }\n\n onMessage(handler: (msg: IncomingMessage) => Promise<void>): void {\n this.handler = handler\n }\n\n async start(): Promise<void> {\n let Discord: any\n\n try {\n Discord = await import(\"discord.js\")\n } catch {\n this.log(\"Discord requires discord.js. Install with:\")\n this.log(\" npm install discord.js\")\n return\n }\n\n const { Client, GatewayIntentBits } = Discord\n\n this.client = new Client({\n intents: [\n GatewayIntentBits.Guilds,\n GatewayIntentBits.GuildMessages,\n GatewayIntentBits.MessageContent,\n GatewayIntentBits.DirectMessages,\n ],\n })\n\n this.client.on(\"ready\", () => {\n this.log(`Discord connected as ${this.client.user?.tag}`)\n })\n\n this.client.on(\"messageCreate\", async (msg: any) => {\n if (!this.handler) return\n if (msg.author.bot) return\n\n // Check if bot is mentioned or it's a DM\n const isMentioned = msg.mentions.users.has(this.client.user?.id)\n const isDM = !msg.guild\n\n if (!isMentioned && !isDM) return\n\n // Strip bot mention from text\n let text = msg.content\n if (this.client.user) {\n text = text.replace(new RegExp(`<@!?${this.client.user.id}>`, \"g\"), \"\").trim()\n }\n\n if (!text) return\n\n const incoming: IncomingMessage = {\n id: msg.id,\n channel: \"discord\",\n accountId: \"default\",\n sender: {\n id: msg.author.id,\n name: msg.author.displayName || msg.author.username,\n username: msg.author.username,\n },\n group: msg.guild ? {\n id: msg.channelId,\n name: msg.channel?.name || msg.channelId,\n } : undefined,\n text,\n replyTo: msg.reference?.messageId,\n timestamp: msg.createdAt,\n raw: msg,\n }\n\n this.handler(incoming).catch((e: any) => {\n this.log(`Error handling message: ${e.message}`)\n })\n })\n\n try {\n await this.client.login(this.token)\n } catch (e: any) {\n this.log(`Discord login failed: ${e.message}`)\n }\n }\n\n async stop(): Promise<void> {\n if (this.client) {\n this.client.destroy()\n this.client = null\n }\n }\n\n async send(msg: OutgoingMessage): Promise<string> {\n if (!this.client) return \"\"\n try {\n const channel = await this.client.channels.fetch(msg.chatId)\n if (!channel?.isTextBased()) return \"\"\n\n const sent = await channel.send({\n content: msg.text,\n ...(msg.replyTo ? { reply: { messageReference: msg.replyTo } } : {}),\n })\n return sent.id\n } catch (e: any) {\n this.log(`Send error: ${e.message}`)\n return \"\"\n }\n }\n\n async editMessage(chatId: string, messageId: string, text: string): Promise<boolean> {\n if (!this.client) return false\n try {\n const channel = await this.client.channels.fetch(chatId)\n if (!channel?.isTextBased()) return false\n const message = await channel.messages.fetch(messageId)\n await message.edit(text)\n return true\n } catch { return false }\n }\n\n async sendTyping(chatId: string): Promise<void> {\n if (!this.client) return\n try {\n const channel = await this.client.channels.fetch(chatId)\n if (channel?.isTextBased()) await channel.sendTyping()\n } catch { /* best-effort */ }\n }\n\n async react(chatId: string, messageId: string, emoji: string = \"👀\"): Promise<void> {\n if (!this.client) return\n try {\n const channel = await this.client.channels.fetch(chatId)\n if (!channel?.isTextBased()) return\n const message = await channel.messages.fetch(messageId)\n await message.react(emoji)\n } catch { /* best-effort */ }\n }\n}\n","import path from \"path\"\nimport fs from \"fs-extra\"\nimport { type PackageJson } from \"type-fest\"\n\nexport function getPackageInfo() {\n const packageJsonPath = path.join(\"package.json\")\n\n return fs.readJSONSync(packageJsonPath) as PackageJson\n}\n"],"mappings":"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","names":["A2AClient","baseUrl","token","res","text","metadata","response","body","reader","decoder","buffer","done","value","lines","line","data","taskId","method","params","h","A2AMesh","config","log","peer","A2AClient","interval","results","name","state","healthy","p","timeout","controller","timer","card","e","peerName","text","agentId","agent","url","headers","res","data","skillId","a","z","readFileSync","existsSync","resolve","loadDotEnv","dir","envPath","content","line","trimmed","eqIdx","key","value","providerConfigSchema","agentConfigSchema","telegramAccountSchema","channelsConfigSchema","cronJobSchema","meshPeerSchema","meshConfigSchema","daemonConfigSchema","expandEnvVars","obj","_match","name","result","loadDaemonConfig","configPath","paths","raw","foundPath","p","parsed","e","expanded","issues","i","validateWorkspaces","config","warnings","id","agent","claudeDir","providerName","providerConfig","cron","account","execa","execFile","buildPrompt","agent","task","historyContext","parts","ctx","envLines","peer","handle","role","buildClaudeArgs","prompt","streaming","resumeSessionId","args","parseClaudeJsonOutput","stdout","data","executeClaudeCode","start","stderr","exitCode","resolve","reject","proc","error","parsed","executeClaudeCodeStreaming","onDelta","fullText","lineBuffer","chunk","lines","line","event","block","delta","resultText","result","executeSdk","apiKey","sdk","query","content","q","message","executeOrchestrator","generate","providerName","executeTask","providers","readFileSync","writeFileSync","existsSync","mkdirSync","readdirSync","statSync","resolve","join","relative","dirname","WikiStore","baseDir","log","article","agentId","entry","filename","filepath","frontmatter","k","v","filter","files","f","entries","file","content","fmMatch","fm","body","get","key","path","meta","existing","fullPath","s","r","t","raw","getArray","m","articles","filePath","relPath","query","maxResults","queryLower","results","score","titleLower","contentLower","occurrences","a","b","message","maxArticles","stopWords","words","w","articleScores","word","matches","maxChars","lines","totalChars","header","chunk","backlinks","links","link","target","aliases","index","md","byType","list","type","x","y","access","totalArticles","byAccess","byOwner","entryFiles","dir","callback","full","readFileSync","writeFileSync","mkdirSync","existsSync","resolve","MAX_HISTORY_CHARS","MAX_MESSAGES","SessionStore","baseDir","agentId","channel","chatId","day","key","safe","file","data","session","senderName","content","claudeSessionId","lines","msg","time","totalChars","sum","m","removed","AgentRegistry","config","log","SessionStore","WikiStore","id","def","text","lower","bestId","bestLen","state","mention","mentionLower","found","agentId","channel","agent","m","task","peers","myHandle","onDelta","chatId","senderName","wikiArticles","wikiContext","resumeSessionId","sessionHistory","historyContext","response","executeTask","entryId","error","s","_MessageRouter","registry","config","hooks","log","mesh","adapter","msg","name","hookResult","chatId","agentId","boundAccount","agentName","replyAccountId","typingTimer","canStream","sentMessageId","lastEditTime","onDelta","_delta","fullText","now","preview","groupContext","messageWithContext","response","errorText","responseText","sentResponseId","e","originalMsg","sourceAgentId","responseMessageId","depth","id","def","m","targetAccountId","sourceAccountId","contextMessage","sentId","messageId","text","parseMode","accountId","emoji","sendTyping","textLower","directory","peer","skill","header","sender","lines","chars","i","entry","line","account","mentionAgent","MessageRouter","__publicField","escapeHtml","text","markdownToTelegramHtml","md","lines","result","inCodeBlock","codeBlockLang","codeBlockLines","inBlockquote","tableHeaders","inTable","i","line","code","langHint","content","convertInline","headerMatch","cells","c","parts","header","ulMatch","indent","olMatch","num","html","wrapFileRefsInCode","_m","label","url","FILE_EXT_TLDS","insideTag","part","TelegramAdapter","accounts","log","handler","entries","i","accountId","config","me","e","chatId","token","msg","maxLen","text","formatted","markdownToTelegramHtml","params","result","messageId","parseMode","trimmed","emoji","offset","updates","update","mediaInfo","hasPhoto","hasVoice","hasAudio","hasVideo","hasDocument","fileId","mime","filePath","fileUrl","res","buffer","ext","mkdirSync","writeFileSync","randomUUID","resolve","join","mediaDir","fileName","localPath","incoming","r","method","url","mkdirSync","writeFileSync","resolve","join","randomUUID","WhatsAppAdapter","config","log","senderPhone","groupName","groupJid","route","normalized","pattern","handler","makeWASocket","useMultiFileAuthState","DisconnectReason","baileys","state","saveCreds","version","v","silentLogger","args","data","update","connection","lastDisconnect","qr","qrcode","statusCode","m","msg","jidShort","hasText","me","remoteJid","myJid","myLid","chatUser","text","msgContent","hasImage","hasAudio","hasVideo","hasDocument","hasSticker","hasMedia","jid","isGroup","chatPhone","p","senderName","resolvedAgent","mediaInfo","buffer","mime","ext","mediaDir","fileName","filePath","e","incoming","sentId","chatId","messageId","emoji","writeFileSync","mkdirSync","existsSync","resolve","parseCronField","field","min","max","values","part","i","range","stepStr","step","start","a","b","getNextCronDate","expression","after","timezone","fields","minutes","hours","daysOfMonth","months","daysOfWeek","fmt","candidate","limit","parts","get","type","p","m","h","dom","mon","dow","CronScheduler","config","registry","hooks","log","id","def","job","j","timer","jobId","nextRun","delay","e","hookResult","startedAt","response","result","runDir","filename","createServer","DiscordAdapter","config","log","handler","Discord","Client","GatewayIntentBits","msg","isMentioned","isDM","text","incoming","e","channel","chatId","messageId","emoji","AgentXDaemon","configPath","loadDaemonConfig","warnings","validateWorkspaces","w","HookRegistry","loadHooks","AgentRegistry","MessageRouter","CronScheduler","A2AMesh","agent","cronJobs","job","status","peer","accounts","telegram","TelegramAdapter","whatsapp","WhatsAppAdapter","discord","DiscordAdapter","host","portStr","port","createServer","req","res","err","path","j","body","readBody","response","result","a","e","data","resolve","reject","chunk","path","fs","getPackageInfo","packageJsonPath"]}