agentix-cli 0.6.0 → 0.9.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 (58) hide show
  1. package/README.md +337 -116
  2. package/dist/agent-QYQVGKLM.js +2 -0
  3. package/dist/chunk-34UAFPK4.js +10 -0
  4. package/dist/chunk-34UAFPK4.js.map +1 -0
  5. package/dist/{chunk-X7UN6JAA.js → chunk-6MKAXEE5.js} +2 -2
  6. package/dist/chunk-BAIQJHQF.js +64 -0
  7. package/dist/chunk-BAIQJHQF.js.map +1 -0
  8. package/dist/chunk-BHDLKX3G.js +6 -0
  9. package/dist/chunk-BHDLKX3G.js.map +1 -0
  10. package/dist/chunk-CJ45Y2IR.js +12 -0
  11. package/dist/chunk-CJ45Y2IR.js.map +1 -0
  12. package/dist/chunk-DSYKYZMT.js +2 -0
  13. package/dist/chunk-DSYKYZMT.js.map +1 -0
  14. package/dist/chunk-IVVVYXPH.js +136 -0
  15. package/dist/chunk-IVVVYXPH.js.map +1 -0
  16. package/dist/{chunk-MGMZNJCE.js → chunk-KXZMYLHQ.js} +27 -27
  17. package/dist/chunk-KXZMYLHQ.js.map +1 -0
  18. package/dist/chunk-SBUX74OU.js +108 -0
  19. package/dist/chunk-SBUX74OU.js.map +1 -0
  20. package/dist/chunk-X32247GM.js +2 -0
  21. package/dist/chunk-X32247GM.js.map +1 -0
  22. package/dist/chunk-ZRYBSI5G.js +23 -0
  23. package/dist/chunk-ZRYBSI5G.js.map +1 -0
  24. package/dist/cli.js +289 -9
  25. package/dist/cli.js.map +1 -1
  26. package/dist/compaction-E3MQRLTL.js +28 -0
  27. package/dist/compaction-E3MQRLTL.js.map +1 -0
  28. package/dist/config-MSWKC466.js +2 -0
  29. package/dist/debug-N3B5NVJU.js +2 -0
  30. package/dist/heal-OTGT5HHJ.js +2 -0
  31. package/dist/heal-OTGT5HHJ.js.map +1 -0
  32. package/dist/index.d.ts +707 -164
  33. package/dist/index.js +2 -2
  34. package/dist/index.js.map +1 -1
  35. package/dist/memory-extract-RGPUPMKU.js +2 -0
  36. package/dist/memory-extract-RGPUPMKU.js.map +1 -0
  37. package/dist/{providers-AVYG63KK.js → providers-G3WZ4RVJ.js} +2 -2
  38. package/dist/providers-G3WZ4RVJ.js.map +1 -0
  39. package/dist/registry-FP6FUOXF.js +2 -0
  40. package/dist/registry-FP6FUOXF.js.map +1 -0
  41. package/dist/subagent-WV7QKQ3L.js +3 -0
  42. package/dist/subagent-WV7QKQ3L.js.map +1 -0
  43. package/dist/usage-dashboard-2TJQBFSH.js +404 -0
  44. package/dist/usage-dashboard-2TJQBFSH.js.map +1 -0
  45. package/package.json +4 -1
  46. package/dist/agent-K2YOEOJ5.js +0 -2
  47. package/dist/chunk-F73GPYCO.js +0 -106
  48. package/dist/chunk-F73GPYCO.js.map +0 -1
  49. package/dist/chunk-MGMZNJCE.js.map +0 -1
  50. package/dist/chunk-WT2UJMBC.js +0 -68
  51. package/dist/chunk-WT2UJMBC.js.map +0 -1
  52. package/dist/chunk-Z4GC5D6D.js +0 -12
  53. package/dist/chunk-Z4GC5D6D.js.map +0 -1
  54. package/dist/heal-UV5A6B5T.js +0 -2
  55. /package/dist/{agent-K2YOEOJ5.js.map → agent-QYQVGKLM.js.map} +0 -0
  56. /package/dist/{chunk-X7UN6JAA.js.map → chunk-6MKAXEE5.js.map} +0 -0
  57. /package/dist/{heal-UV5A6B5T.js.map → config-MSWKC466.js.map} +0 -0
  58. /package/dist/{providers-AVYG63KK.js.map → debug-N3B5NVJU.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agents/runtime.ts","../src/agents/sessions.ts","../src/wiki/store.ts","../src/wiki/hub.ts","../src/daemon/rate-limit.ts","../src/agents/context.ts","../src/agents/memory-store.ts","../src/agents/message-queue.ts","../src/agents/bootstrap.ts","../src/agents/registry.ts"],"sourcesContent":["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. \"@my_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 /** Platform user ID (e.g. Telegram user ID) */\n senderId?: string\n /** Platform username (e.g. @username) */\n senderUsername?: string\n group?: string\n /** Stable chat ID for session keying (e.g. \"project:issue:123\" for GitLab) */\n chatId?: 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 /** Verified channel metadata (from adapter) */\n channelMeta?: {\n agents?: Array<{ id: string; name: string; handle?: string }>\n project?: string\n issue?: { type: string; iid: string; title: string }\n facts?: string[]\n }\n }\n}\n\nexport interface AgentResponse {\n content: string\n error?: string\n tokensUsed?: number\n duration?: number\n claudeSessionId?: string\n usage?: TokenUsage // Real token counts from Claude's JSON output\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 — skip if historyContext is provided (context engine handles it)\n if (task.context && !historyContext) {\n const ctx = task.context\n const envLines: string[] = [\"\", \"[Environment]\"]\n const isGitLab = ctx.channel === \"gitlab\" || ctx.channel?.startsWith(\"webhook:\")\n const isTelegram = ctx.channel === \"telegram\"\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 (isGitLab) {\n envLines.push(\"\")\n envLines.push(\"[IMPORTANT: You are responding to a GitLab comment/event]\")\n envLines.push(\"- Keep it short — 3-5 lines for the main message. Humans scan, not read\")\n envLines.push(\"- Lead with the result or action, not a narration of what you plan to do\")\n envLines.push(\"- Use <details><summary>Details</summary>\\\\n\\\\ncontent\\\\n</details> for verbose output (logs, full commands, step-by-step)\")\n envLines.push(\"- Do NOT mention Telegram handles — they don't work on GitLab\")\n envLines.push(\"- Do NOT try to delegate to other agents — reply directly\")\n envLines.push(\"- Reference issues with #IID and MRs with !IID\")\n }\n\n if (isTelegram && 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 */\nexport interface TokenUsage {\n inputTokens: number\n outputTokens: number\n cacheReadTokens: number\n cacheCreateTokens: number\n}\n\nfunction parseClaudeJsonOutput(stdout: string): { text: string; sessionId?: string; usage?: TokenUsage } {\n try {\n const data = JSON.parse(stdout)\n const usage = data.usage ? {\n inputTokens: data.usage.input_tokens || 0,\n outputTokens: data.usage.output_tokens || 0,\n cacheReadTokens: data.usage.cache_read_input_tokens || 0,\n cacheCreateTokens: data.usage.cache_creation_input_tokens || 0,\n } : undefined\n\n return {\n text: data.result || data.content || \"\",\n sessionId: data.session_id,\n usage,\n }\n } catch {\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 // Always inject context (landscape, rules, channel info) even on resume.\n // Claude CLI --resume carries its own conversation history, but the\n // landscape + rules must be fresh so the agent sees capability updates.\n const prompt = buildPrompt(agent, task, 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 || \"user\") },\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 const parsed = parseClaudeJsonOutput(stdout)\n\n return {\n content: parsed.text,\n duration: Date.now() - start,\n claudeSessionId: parsed.sessionId,\n usage: parsed.usage,\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 // Always inject context (landscape, rules, channel info) even on resume.\n // Claude CLI --resume carries its own conversation history, but the\n // landscape + rules must be fresh so the agent sees capability updates.\n const prompt = buildPrompt(agent, task, 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, mkdirSync, existsSync, readdirSync } 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\nconst STALE_SESSION_MINUTES = 15 // Resume sessions idle for less than this; rebuild if older\n\n/** Session has a compacted summary prepended to its messages */\nconst COMPACTION_MARKER = \"[Compacted conversation summary\"\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 * Check if a Claude session is stale (idle too long for --resume to be useful).\n * When stale, the resumed context will be too far behind — better to start fresh.\n */\n isSessionStale(agentId: string, channel: string, chatId: string): boolean {\n const session = this.getSession(agentId, channel, chatId)\n if (!session.claudeSessionId) return false\n const elapsed = Date.now() - new Date(session.updatedAt).getTime()\n return elapsed > STALE_SESSION_MINUTES * 60 * 1000\n }\n\n /**\n * Build a summary of recent messages from OTHER sessions for the same agent today.\n * This bridges the cross-chat amnesia gap — if someone shared info in a DM,\n * the group session gets a hint about it.\n */\n getCrossSessionSummary(agentId: string, channel: string, chatId: string): string {\n const day = new Date().toISOString().slice(0, 10)\n const currentKey = this.sessionKey(agentId, channel, chatId)\n\n try {\n const files = readdirSync(this.sessionsDir).filter(f =>\n f.startsWith(agentId.replace(/[^a-zA-Z0-9_:-]/g, \"_\")) &&\n f.includes(day) &&\n f.endsWith(\".json\")\n )\n\n const hints: string[] = []\n\n for (const file of files) {\n try {\n const data = JSON.parse(readFileSync(resolve(this.sessionsDir, file), \"utf-8\")) as Session\n if (data.id === currentKey) continue // skip own session\n if (data.messages.length === 0) continue\n\n // Take the last few messages as a hint\n const recent = data.messages.slice(-4)\n const isDM = !data.chatId.startsWith(\"-\") && /^\\d+$/.test(data.chatId)\n const scope = isDM ? \"DM\" : data.chatId\n const lines = recent.map(m => {\n const time = m.timestamp.slice(11, 16)\n return ` [${time}] ${m.name || m.role}: ${m.content.slice(0, 200)}`\n })\n hints.push(`From ${scope} (${data.channel}):\\n${lines.join(\"\\n\")}`)\n } catch {\n // Skip corrupted files\n }\n }\n\n if (hints.length === 0) return \"\"\n\n return [\n \"[Cross-chat context — recent activity from your other conversations today]\",\n ...hints,\n \"[End cross-chat context — the user in THIS chat may be referring to actions from above]\",\n \"\",\n ].join(\"\\n\")\n } catch {\n return \"\"\n }\n }\n\n /**\n * Check if session history needs compaction and compact if so.\n * Call this after adding messages. Returns true if compaction was performed.\n */\n async compactIfNeeded(\n agentId: string,\n channel: string,\n chatId: string,\n memoryStore?: import(\"./memory-store\").MemoryStore,\n ): Promise<boolean> {\n const session = this.getSession(agentId, channel, chatId)\n const { needsCompaction, compactSession, applyCompaction } = await import(\"./compaction\")\n\n if (!needsCompaction(session.messages)) return false\n\n const result = await compactSession(session.messages, agentId, memoryStore)\n if (result.compactedCount === 0) return false\n\n session.messages = applyCompaction(session.messages, result)\n session.updatedAt = new Date().toISOString()\n\n // Clear Claude session ID — the compacted context needs a fresh session\n delete session.claudeSessionId\n\n this.save(session)\n return true\n }\n\n /**\n * Check if current session already has a compacted summary.\n */\n hasCompaction(agentId: string, channel: string, chatId: string): boolean {\n const session = this.getSession(agentId, channel, chatId)\n return session.messages.length > 0 &&\n session.messages[0].content.startsWith(COMPACTION_MARKER)\n }\n\n /**\n * Clear the stored Claude session ID so next invocation starts fresh.\n */\n clearClaudeSessionId(agentId: string, channel: string, chatId: string): void {\n const session = this.getSession(agentId, channel, chatId)\n delete session.claudeSessionId\n session.updatedAt = new Date().toISOString()\n this.save(session)\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 { readFileSync, writeFileSync, appendFileSync, existsSync, mkdirSync, readdirSync, statSync } from \"fs\"\nimport { resolve, join, relative, dirname } from \"path\"\nimport type { WikiArticle, WikiArticleMeta, WikiEntry, WikiIndex, WikiAccess } from \"./types\"\nimport { buildIndex, scoreAll } from \"../memory/bm25\"\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 // Initialize schema if missing\n this.ensureSchema()\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 (!agentId) return false\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 this.appendLog(\"ingest\", `${entry.id} from ${entry.agentId} via ${entry.source}`)\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 // LLM picks the path. We just write the file.\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 `tags: [${(meta.tags || []).map(t => `\"${t}\"`).join(\", \")}]`,\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 `sources: [${meta.sources.map(s => `\"${s}\"`).join(\", \")}]`,\n )\n frontmatter.push(\"---\", \"\", content)\n\n writeFileSync(fullPath, frontmatter.join(\"\\n\"))\n const action = existing ? \"update\" : \"create\"\n this.appendLog(action, `${meta.title} [${(meta.tags || []).slice(0, 5).join(\", \")}] by ${agentId} at ${path}`)\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 // Collect tags from all legacy fields + explicit tags\n const tags = [\n ...getArray(\"tags\"),\n // Pull legacy fields into tags for backwards compat\n ...(get(\"kind\") ? [get(\"kind\")] : []),\n ...(get(\"type\") ? [get(\"type\")] : []),\n ].filter((v, i, a) => v && a.indexOf(v) === i) // dedupe\n\n return {\n meta: {\n title: get(\"title\"),\n tags,\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 sources: getArray(\"sources\"),\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 articles: WikiArticle[] = []\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 articles.push(article)\n })\n\n if (articles.length === 0) return []\n\n // BM25 over article content\n const docs = articles.map((a) => a.content)\n const index = buildIndex(docs)\n const bm25Scores = scoreAll(query, index)\n const scoreMap = new Map(bm25Scores.map((r) => [r.docIndex, r.score]))\n\n const results = articles.map((article, i) => {\n let score = scoreMap.get(i) ?? 0\n // Additive bonuses for title and tag matches\n if (article.meta.title.toLowerCase().includes(queryLower)) score += 10\n if (article.meta.tags?.some(t => t.toLowerCase().includes(queryLower))) score += 5\n return { article, score }\n })\n\n return results\n .filter((r) => r.score > 0)\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 const articles: WikiArticle[] = []\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 articles.push(article)\n })\n\n if (articles.length === 0) return []\n\n // Single BM25 pass over title + tags + content\n const docs = articles.map(\n (a) => `${a.meta.title} ${(a.meta.tags || []).join(\" \")} ${a.content}`,\n )\n const index = buildIndex(docs)\n const scored = scoreAll(message, index)\n\n return scored\n .slice(0, maxArticles)\n .map((s) => articles[s.docIndex])\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.tags || []).slice(0, 3).join(\", \")}]`\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 tags: article.meta.tags || [],\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 sources: article.meta.sources,\n lastUpdated: article.meta.lastUpdated,\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 type = (a as any).type || a.access || \"public\"\n const list = byType.get(type) || []\n list.push(a)\n byType.set(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 this.appendLog(\"rebuild-index\", `${articles.length} articles indexed`)\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 for (const tag of (article.meta.tags || [])) {\n byType[tag] = (byType[tag] || 0) + 1\n }\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 // --- Log (chronological, append-only) ---\n\n /**\n * Append an entry to log.md.\n * Format: ## [YYYY-MM-DD HH:MM] action | details\n */\n appendLog(action: string, details: string): void {\n const logPath = resolve(this.baseDir, \"log.md\")\n const timestamp = new Date().toISOString().replace(\"T\", \" \").slice(0, 16)\n const entry = `## [${timestamp}] ${action} | ${details}\\n\\n`\n\n if (!existsSync(logPath)) {\n writeFileSync(logPath, \"# Wiki Log\\n\\nChronological record of all wiki operations.\\n\\n\")\n }\n\n appendFileSync(logPath, entry)\n }\n\n /**\n * Get recent log entries.\n */\n getLog(limit: number = 20): string[] {\n const logPath = resolve(this.baseDir, \"log.md\")\n if (!existsSync(logPath)) return []\n\n const content = readFileSync(logPath, \"utf-8\")\n const entries = content.split(/^## /m).filter(e => e.startsWith(\"[\")).slice(-limit)\n return entries.map(e => e.trim())\n }\n\n // --- Schema ---\n\n /**\n * Create _schema.md if it doesn't exist.\n * This tells the LLM how to operate on the wiki.\n */\n private ensureSchema(): void {\n const schemaPath = resolve(this.baseDir, \"_schema.md\")\n if (existsSync(schemaPath)) return\n\n const schema = `# Wiki Schema\n\nA personal wiki maintained by LLMs. Karpathy pattern: plain files, aggressive tagging,\nstructure emerges from data. The wiki is a compounding artifact.\n\n## Structure\n\n\\`\\`\\`\nwiki/\n _schema.md # This file\n worldview.md # YOUR mental model — the LLM reads this during absorb\n raw/entries/ # Immutable raw sources (conversations, imports, anything)\n [LLM-chosen dirs] # Structure emerges from data — the LLM picks paths\n\\`\\`\\`\n\nThe LLM decides how to organize articles. You describe YOUR world in worldview.md.\n\n## Article Format\n\n\\`\\`\\`yaml\n---\ntitle: \"Staging Deployment Process\"\ntags: [\"deploy\", \"staging\", \"devops\", \"process\", \"2026-04-06\"]\nowner: devops-agent\naccess: public\ncreated: 2026-04-06\nlast_updated: 2026-04-06\nsources: [\"entry-id-1\", \"entry-id-2\"]\n---\n\nArticle content with [[wikilinks]] and section tags.\n\n## Deploy Steps\n<!-- tags: process, runbook, staging -->\nContent specific to this section...\n\\`\\`\\`\n\n## Tags\n\nTags are the primary context-narrowing mechanism. The more tags, the better.\n\nTag aggressively:\n- **Who**: people, agents, teams involved\n- **What**: project, client, topic, technology\n- **When**: dates, periods, milestones\n- **Where**: server, environment, channel\n- **How**: process, decision, pattern\n- **Your terms**: whatever vocabulary makes sense in YOUR world\n\nSection tags (\\`<!-- tags: ... -->\\`) let different parts of an article\nmatch different queries. A deploy article might have sections tagged\n\"runbook\" and \"incident\" separately.\n\n## Operations\n\n### Absorb\nRead raw entries → read worldview.md → tag aggressively → create/update articles.\nAlso identify GAPS: \"We mention X but have no article for it.\"\n\n### Query\nMatch by tags first → then keyword within matched articles → synthesize.\nIf agent is working on a specific project, only send content tagged for that project.\n\n### Lint\nCheck for: orphan articles, broken [[wikilinks]], untagged articles,\narticles over 100 lines that should split, mentioned-but-missing topics.\n\n## Worldview\n\nEdit \\`worldview.md\\` to describe YOUR world. This is not a schema — it's your\nmental model. The LLM reads it during absorb to understand where things go.\n\nExample worldview.md:\n\\`\\`\\`\nI'm the founder of Acme Corp.\nWe build software products.\nOur agents: Marketing Bot, DevOps Bot, Coordinator.\nClients: ClientA (enterprise), ClientB (startup).\nInfrastructure: local dev machine, cloud server.\nWe use GitLab for version control.\n\\`\\`\\`\n`\n\n writeFileSync(schemaPath, schema)\n this.log(\"Created _schema.md\")\n }\n\n // --- Wikilinks and Backlinks ---\n\n /**\n * Extract all [[wikilinks]] from article content.\n */\n extractWikilinks(content: string): string[] {\n const matches = content.match(/\\[\\[([^\\]]+)\\]\\]/g) || []\n return matches.map(m => m.replace(/\\[\\[|\\]\\]/g, \"\"))\n }\n\n /**\n * Build backlinks index: for each article, which other articles link to it.\n */\n buildBacklinks(): Record<string, string[]> {\n const backlinks: Record<string, string[]> = {}\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\" || relPath === \"log.md\") return\n\n const content = readFileSync(filePath, \"utf-8\")\n const links = this.extractWikilinks(content)\n\n for (const link of links) {\n if (!backlinks[link]) backlinks[link] = []\n backlinks[link].push(relPath)\n }\n })\n\n // Save\n writeFileSync(\n resolve(this.baseDir, \"_backlinks.json\"),\n JSON.stringify(backlinks, null, 2),\n )\n\n return backlinks\n }\n\n /**\n * Get backlinks for a specific article title.\n */\n getBacklinks(title: string): string[] {\n const path = resolve(this.baseDir, \"_backlinks.json\")\n if (!existsSync(path)) return []\n try {\n const data = JSON.parse(readFileSync(path, \"utf-8\"))\n return data[title] || []\n } catch {\n return []\n }\n }\n\n // --- Tag-based filtering (Karpathy: tags are the context narrowing mechanism) ---\n\n /**\n * Find articles matching ANY of the given tags.\n * This is how agents get relevant context — only articles tagged with\n * the client/project/topic they're working on.\n */\n findByTags(tags: string[], agentId?: string, limit: number = 10): WikiArticle[] {\n const lowerTags = tags.map(t => t.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) return\n if (agentId && !this.canRead(article.meta, agentId)) return\n\n // Score: how many of the requested tags match?\n const articleTags = (article.meta.tags || []).map(t => t.toLowerCase())\n // Also check section tags: <!-- tags: foo, bar -->\n const sectionTags = (article.content.match(/<!--\\s*tags?:\\s*([^>]+)\\s*-->/gi) || [])\n .flatMap(m => m.replace(/<!--\\s*tags?:\\s*|\\s*-->/gi, \"\").split(\",\").map(t => t.trim().toLowerCase()))\n\n const allTags = [...articleTags, ...sectionTags]\n const score = lowerTags.filter(t => allTags.includes(t)).length\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, limit)\n .map(r => r.article)\n }\n\n /**\n * Get all unique tags across all articles.\n */\n getAllTags(): Map<string, number> {\n const tagCounts = 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?.meta.tags) return\n\n for (const tag of article.meta.tags) {\n tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1)\n }\n })\n\n return tagCounts\n }\n\n // --- Worldview (user's mental model — input to absorb) ---\n\n /**\n * Get the worldview file. This is the user's description of their world —\n * the LLM uses it during absorb to know where things go.\n * Returns null if not set.\n */\n getWorldview(): string | null {\n const path = resolve(this.baseDir, \"worldview.md\")\n if (!existsSync(path)) return null\n return readFileSync(path, \"utf-8\")\n }\n\n /**\n * Set the worldview. The user describes their world: companies, clients,\n * projects, team, processes. The LLM uses this as context during absorb.\n */\n setWorldview(content: string): void {\n writeFileSync(resolve(this.baseDir, \"worldview.md\"), content)\n this.appendLog(\"worldview\", \"Updated worldview\")\n }\n\n // --- Lint ---\n\n /**\n * Run a lint pass on the wiki. Returns issues found.\n */\n lint(): Array<{ type: string; article: string; message: string }> {\n const issues: Array<{ type: string; article: string; message: string }> = []\n const allTitles = new Set<string>()\n const allLinks = new Map<string, string[]>() // article -> outbound links\n const articlePaths = new Map<string, string>() // title -> path\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\" || relPath === \"log.md\") return\n\n const article = this.readArticle(relPath)\n if (!article) return\n\n allTitles.add(article.meta.title)\n articlePaths.set(article.meta.title, relPath)\n\n const links = this.extractWikilinks(article.content)\n allLinks.set(relPath, links)\n\n // Check: article too long\n const lines = article.content.split(\"\\n\").length\n if (lines > 100) {\n issues.push({\n type: \"bloated\",\n article: relPath,\n message: `${lines} lines — consider splitting`,\n })\n }\n\n // Check: no sources\n if (!article.meta.sources?.length) {\n issues.push({\n type: \"unsourced\",\n article: relPath,\n message: \"No sources listed in frontmatter\",\n })\n }\n\n // Check: stub (too short)\n if (lines < 10 && article.content.trim().length < 100) {\n issues.push({\n type: \"stub\",\n article: relPath,\n message: \"Very short article — needs enrichment\",\n })\n }\n })\n\n // Check: broken wikilinks\n for (const [articlePath, links] of allLinks) {\n for (const link of links) {\n if (!allTitles.has(link)) {\n issues.push({\n type: \"broken-link\",\n article: articlePath,\n message: `[[${link}]] — target article not found`,\n })\n }\n }\n }\n\n // Check: orphan articles (no inbound links)\n const backlinks = this.buildBacklinks()\n for (const [title, path] of articlePaths) {\n if (!backlinks[title] || backlinks[title].length === 0) {\n issues.push({\n type: \"orphan\",\n article: path,\n message: `No other articles link to \"${title}\"`,\n })\n }\n }\n\n this.appendLog(\"lint\", `Found ${issues.length} issues`)\n return issues\n }\n\n // --- Absorb summary (for automated cron) ---\n\n /**\n * Get unabsorbed entries (entries not referenced by any article's sources field).\n */\n getUnabsorbedEntries(): WikiEntry[] {\n const allSources = new Set<string>()\n\n // Collect all source IDs referenced by articles\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?.meta.sources) {\n for (const s of article.meta.sources) allSources.add(s)\n }\n })\n\n // Find entries not in any article's sources\n const entries = this.listEntries()\n return entries.filter(e => !allSources.has(e.id))\n }\n\n /**\n * Build an absorb prompt for unprocessed entries.\n * Returns a prompt string an agent can execute to compile entries into articles.\n */\n buildAbsorbPrompt(maxEntries: number = 20): string | null {\n const unabsorbed = this.getUnabsorbedEntries().slice(0, maxEntries)\n if (unabsorbed.length === 0) return null\n\n const entrySummaries = unabsorbed.map(e =>\n `[${e.date} ${e.agentId} via ${e.source}] ${e.content.slice(0, 200)}`\n ).join(\"\\n\\n\")\n\n return `/wiki absorb\\n\\nThere are ${unabsorbed.length} unprocessed entries. Read each, understand what it means, and create or update wiki articles.\\n\\n${entrySummaries}`\n }\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 { WikiStore } from \"./store\"\nimport { resolve } from \"path\"\nimport { existsSync, readdirSync, mkdirSync } from \"fs\"\nimport type { WikiEntry } from \"./types\"\n\nexport type WikiMode = \"flat\" | \"graph\" | \"unified\"\n\n/**\n * WikiHub: manages per-agent wikis with a shared raw entry pool.\n * Supports two compilation modes:\n * - flat: Karpathy pattern — tags, LLM-chosen paths, worldview, gap detection\n * - graph: Knowledge graph — kind, parent, hierarchy, events, entities\n *\n * Both modes share the same raw entries. Articles stored separately:\n * agents/<id>/flat/ ← Karpathy compilation\n * agents/<id>/graph/ ← Knowledge graph compilation\n */\nexport class WikiHub {\n private baseDir: string\n private agentsDir: string\n private mode: WikiMode\n private sharedStore: WikiStore\n private agentStores: Map<string, WikiStore> = new Map()\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-hub]\"),\n mode: WikiMode = \"graph\",\n ) {\n this.baseDir = baseDir\n this.agentsDir = resolve(baseDir, \"agents\")\n this.mode = mode\n this.log = log\n\n mkdirSync(this.agentsDir, { recursive: true })\n this.sharedStore = new WikiStore(baseDir, log)\n }\n\n getMode(): WikiMode { return this.mode }\n\n /**\n * Get or create the wiki store for a specific agent (mode-aware).\n * flat: agents/<id>/flat/\n * graph: agents/<id>/graph/\n */\n getAgentWiki(agentId: string): WikiStore {\n const key = `${agentId}:${this.mode}`\n if (this.agentStores.has(key)) return this.agentStores.get(key)!\n\n const agentDir = resolve(this.agentsDir, agentId, this.mode)\n const store = new WikiStore(agentDir, this.log)\n this.agentStores.set(key, store)\n return store\n }\n\n getSharedStore(): WikiStore {\n return this.sharedStore\n }\n\n listAgents(): string[] {\n const agents = new Set<string>()\n\n const entries = this.sharedStore.listEntries()\n for (const e of entries) agents.add(e.agentId)\n\n if (existsSync(this.agentsDir)) {\n for (const dir of readdirSync(this.agentsDir)) {\n if (!dir.startsWith(\"_\") && !dir.startsWith(\".\")) {\n agents.add(dir)\n }\n }\n }\n\n return [...agents].sort()\n }\n\n getAgentEntries(agentId: string): WikiEntry[] {\n return this.sharedStore.listEntries({ agentId })\n }\n\n getUnabsorbedEntries(agentId: string): WikiEntry[] {\n const agentWiki = this.getAgentWiki(agentId)\n const agentEntries = this.getAgentEntries(agentId)\n\n const absorbedIds = new Set<string>()\n const index = agentWiki.rebuildIndex()\n for (const article of index.articles) {\n if (article.sources) {\n for (const s of article.sources) absorbedIds.add(s)\n }\n }\n\n return agentEntries.filter(e => !absorbedIds.has(e.id))\n }\n\n summary(): AgentWikiSummary[] {\n const agents = this.listAgents()\n return agents.map(agentId => {\n const entries = this.getAgentEntries(agentId)\n const wiki = this.getAgentWiki(agentId)\n const index = wiki.rebuildIndex()\n const unabsorbed = this.getUnabsorbedEntries(agentId)\n\n return {\n agentId,\n totalEntries: entries.length,\n totalArticles: index.articles.length,\n unabsorbed: unabsorbed.length,\n articles: index.articles,\n }\n })\n }\n}\n\nexport interface AgentWikiSummary {\n agentId: string\n totalEntries: number\n totalArticles: number\n unabsorbed: number\n articles: Array<{ title: string; path: string; tags?: string[] }>\n}\n","// --- Rate limiter for agent tasks ---\n// Prevents message floods from exhausting Claude API/subscription.\n// Per-agent, sliding window.\n\nexport class RateLimiter {\n private windows: Map<string, number[]> = new Map()\n private maxPerMinute: number\n private maxPerHour: number\n\n constructor(maxPerMinute: number = 10, maxPerHour: number = 100) {\n this.maxPerMinute = maxPerMinute\n this.maxPerHour = maxPerHour\n }\n\n /**\n * Check if an agent can process a task. Returns true if allowed.\n */\n check(agentId: string): { allowed: boolean; reason?: string } {\n const now = Date.now()\n const timestamps = this.windows.get(agentId) || []\n\n // Clean old entries (older than 1 hour)\n const hourAgo = now - 3600_000\n const recent = timestamps.filter(t => t > hourAgo)\n\n // Check per-minute\n const minuteAgo = now - 60_000\n const lastMinute = recent.filter(t => t > minuteAgo).length\n if (lastMinute >= this.maxPerMinute) {\n return { allowed: false, reason: `Rate limit: ${lastMinute}/${this.maxPerMinute} per minute` }\n }\n\n // Check per-hour\n if (recent.length >= this.maxPerHour) {\n return { allowed: false, reason: `Rate limit: ${recent.length}/${this.maxPerHour} per hour` }\n }\n\n // Record this request\n recent.push(now)\n this.windows.set(agentId, recent)\n\n return { allowed: true }\n }\n\n /**\n * Get current usage for an agent.\n */\n usage(agentId: string): { lastMinute: number; lastHour: number } {\n const now = Date.now()\n const timestamps = this.windows.get(agentId) || []\n return {\n lastMinute: timestamps.filter(t => t > now - 60_000).length,\n lastHour: timestamps.filter(t => t > now - 3600_000).length,\n }\n }\n}\n","// --- Agent Context Engine ---\n//\n// Structured, layered context with token budget management.\n// Each context layer has a priority, max tokens, and rules.\n//\n// Layers (highest priority first):\n// 1. Channel — where the message came from + channel-specific rules\n// 2. Scope — group/personal/project + scope-specific constraints\n// 3. Landscape — world model: team roster, channels, rules (cached at startup)\n// 4. Identity — who the agent is, what it can do\n// 5. Intent — what the user is asking about (extracted from message)\n// 6. Artifacts — project, issue, MR, file references\n// 7. History — group conversation log or session history\n// 8. Wiki — relevant knowledge articles\n//\n// Token budget: each layer gets a max allocation. Total capped at configurable limit.\n// Layers are rendered top-down; if budget exhausted, lower layers are truncated or skipped.\n\nexport interface ContextLayer {\n name: string\n priority: number // lower = higher priority (1 = most important)\n maxTokens: number // max tokens for this layer\n content: string // rendered text\n tags: string[] // metadata tags for filtering/matching\n rules?: string[] // constraints/instructions specific to this layer\n}\n\nexport interface ContextConfig {\n /** Total token budget for all context combined (default: 4000) */\n totalBudget: number\n /** Per-layer budgets override (layer name -> max tokens) */\n layerBudgets?: Record<string, number>\n}\n\nconst DEFAULT_CONFIG: ContextConfig = {\n totalBudget: 6000,\n layerBudgets: {\n channel: 200,\n scope: 200,\n landscape: 800,\n identity: 200,\n bootstrap: 500,\n intent: 200,\n artifacts: 500,\n memory: 600,\n history: 1200,\n \"cross-chat\": 800,\n wiki: 1000,\n },\n}\n\n// Rough estimate: 1 token ≈ 4 chars for English\nconst CHARS_PER_TOKEN = 4\n\nexport interface ContextInput {\n // Channel layer\n channel: string // \"telegram\", \"whatsapp\", \"gitlab\", \"discord\"\n channelScope?: \"group\" | \"personal\" | \"project\"\n\n // Bootstrap identity files (from workspace)\n bootstrapContext?: string // from buildBootstrapContext()\n\n // Scope layer\n groupName?: string\n projectPath?: string // \"org/my-project\"\n issueMR?: { type: string; iid: string; title: string }\n\n // Identity layer\n agentId: string\n agentName: string\n agentHandle?: string // \"@my_bot\"\n systemPrompt?: string\n\n // Participants\n sender: string\n senderId?: string // platform user ID (e.g. Telegram user ID)\n senderUsername?: string // platform username (e.g. @username)\n senderRole?: string // \"user\", \"agent:other-agent\"\n\n // Landscape (cached world model from LandscapeBuilder)\n landscape?: string\n\n // Channel meta (verified facts from the channel adapter — prevents hallucination)\n channelMeta?: {\n agents?: Array<{ id: string; name: string; handle?: string }>\n project?: string\n issue?: { type: string; iid: string; title: string }\n facts?: string[]\n }\n\n // Artifacts\n mediaPath?: string\n mediaType?: string\n replyToText?: string\n\n // Memory (persistent cross-session facts)\n memoryContext?: string // from MemoryStore.buildContext()\n\n // History\n groupHistory?: string // from GroupLog.buildContext()\n sessionHistory?: string // from SessionStore.buildHistoryContext()\n crossChatContext?: string // from SessionStore.getCrossSessionSummary()\n\n // Wiki\n wikiContext?: string // from WikiStore.buildContext()\n\n // Message\n message: string\n}\n\n/**\n * Build optimized context string from structured input.\n * Respects token budgets per layer and total cap.\n */\nexport function buildAgentContext(input: ContextInput, config: ContextConfig = DEFAULT_CONFIG): string {\n const layers = buildLayers(input, config)\n\n // Sort by priority (lower = first)\n layers.sort((a, b) => a.priority - b.priority)\n\n // Render within budget\n const parts: string[] = []\n let totalChars = 0\n const maxChars = config.totalBudget * CHARS_PER_TOKEN\n\n for (const layer of layers) {\n if (!layer.content) continue\n\n const layerMaxChars = layer.maxTokens * CHARS_PER_TOKEN\n const trimmed = layer.content.length > layerMaxChars\n ? layer.content.slice(0, layerMaxChars) + \"...\"\n : layer.content\n\n if (totalChars + trimmed.length > maxChars) {\n // Budget exhausted — add what fits or skip\n const remaining = maxChars - totalChars\n if (remaining > 100) {\n parts.push(trimmed.slice(0, remaining) + \"...\")\n }\n break\n }\n\n parts.push(trimmed)\n totalChars += trimmed.length\n }\n\n return parts.join(\"\\n\\n\")\n}\n\n/**\n * Build individual context layers from input.\n */\nfunction buildLayers(input: ContextInput, config: ContextConfig): ContextLayer[] {\n const budget = (name: string, fallback: number) =>\n config.layerBudgets?.[name] ?? fallback\n\n const layers: ContextLayer[] = []\n\n // 1. Channel layer\n layers.push(buildChannelLayer(input, budget(\"channel\", 200)))\n\n // 2. Scope layer\n layers.push(buildScopeLayer(input, budget(\"scope\", 200)))\n\n // 3. Landscape (cached world model — team, channels, rules)\n if (input.landscape) {\n layers.push({\n name: \"landscape\",\n priority: 3,\n maxTokens: budget(\"landscape\", 350),\n content: input.landscape,\n tags: [\"landscape\", \"world-model\"],\n })\n }\n\n // 4. Identity (only first line of systemPrompt — agent already has CLAUDE.md)\n if (input.systemPrompt) {\n layers.push({\n name: \"identity\",\n priority: 4,\n maxTokens: budget(\"identity\", 200),\n content: input.systemPrompt.split(\"\\n\")[0],\n tags: [\"identity\", input.agentId],\n })\n }\n\n // 4.5 Bootstrap identity files (SOUL.md, IDENTITY.md, USER.md, AGENTS.md)\n if (input.bootstrapContext) {\n layers.push({\n name: \"bootstrap\",\n priority: 4.5,\n maxTokens: budget(\"bootstrap\", 500),\n content: input.bootstrapContext,\n tags: [\"bootstrap\", \"identity\", \"personality\"],\n })\n }\n\n // 5. Intent (extracted keywords from message)\n // Lightweight — just tag detection, not LLM-based\n const intentTags = extractIntentTags(input.message)\n if (intentTags.length) {\n layers.push({\n name: \"intent\",\n priority: 5,\n maxTokens: budget(\"intent\", 200),\n content: `[Intent: ${intentTags.join(\", \")}]`,\n tags: intentTags,\n })\n }\n\n // 6. Artifacts (media, reply-to, issue/MR context)\n const artifactLines: string[] = []\n if (input.replyToText) {\n artifactLines.push(`[Replying to]: ${input.replyToText.slice(0, 300)}`)\n }\n if (input.mediaPath) {\n artifactLines.push(`[Attached file: ${input.mediaPath}]`)\n artifactLines.push(`[File type: ${input.mediaType || \"unknown\"}]`)\n if (input.mediaType?.startsWith(\"image/\")) artifactLines.push(\"Please view this image and respond to it.\")\n else if (input.mediaType?.startsWith(\"audio/\")) artifactLines.push(\"Please transcribe this audio and respond.\")\n }\n if (input.issueMR) {\n artifactLines.push(`[${input.issueMR.type} #${input.issueMR.iid}: ${input.issueMR.title}]`)\n }\n if (artifactLines.length) {\n layers.push({\n name: \"artifacts\",\n priority: 6,\n maxTokens: budget(\"artifacts\", 500),\n content: artifactLines.join(\"\\n\"),\n tags: [\"artifacts\", ...(input.mediaType ? [\"media\"] : [])],\n })\n }\n\n // 6.5 Agent memory (persistent cross-session facts from Haiku extraction)\n if (input.memoryContext) {\n layers.push({\n name: \"memory\",\n priority: 6.5,\n maxTokens: budget(\"memory\", 600),\n content: input.memoryContext,\n tags: [\"memory\", \"persistent\"],\n })\n }\n\n // 7. History (group > session — prefer group if available)\n const history = input.groupHistory || input.sessionHistory\n if (history) {\n layers.push({\n name: \"history\",\n priority: 7,\n maxTokens: budget(\"history\", 1200),\n content: history,\n tags: [\"history\", \"conversation\"],\n })\n }\n\n // 7b. Cross-chat context (bridges DM ↔ group amnesia)\n if (input.crossChatContext) {\n layers.push({\n name: \"cross-chat\",\n priority: 7,\n maxTokens: budget(\"cross-chat\", 800),\n content: input.crossChatContext,\n tags: [\"history\", \"cross-chat\"],\n })\n }\n\n // 8. Wiki knowledge\n if (input.wikiContext) {\n layers.push({\n name: \"wiki\",\n priority: 8,\n maxTokens: budget(\"wiki\", 1000),\n content: input.wikiContext,\n tags: [\"wiki\", \"knowledge\"],\n })\n }\n\n return layers\n}\n\n/**\n * Build channel-specific context with rules.\n */\nfunction buildChannelLayer(input: ContextInput, maxTokens: number): ContextLayer {\n const lines: string[] = [`Channel: ${input.channel}`]\n const rules: string[] = []\n const tags = [input.channel]\n\n switch (input.channel) {\n case \"telegram\":\n if (input.agentHandle) lines.push(`Your handle: ${input.agentHandle}`)\n lines.push(`From: ${input.sender}`)\n if (input.senderId) lines.push(`Telegram user ID: ${input.senderId}`)\n if (input.senderUsername) lines.push(`Username: @${input.senderUsername}`)\n rules.push(\"Format responses using Telegram-compatible markdown\")\n rules.push(\"Be brief — 2-4 sentences max for the main point. Humans scan, not read\")\n rules.push(\"Lead with the action or answer, skip preamble\")\n break\n\n case \"whatsapp\":\n lines.push(`From: ${input.sender}`)\n rules.push(\"Be brief — 2-3 sentences max. WhatsApp is mobile-first\")\n rules.push(\"No rich formatting — plain text only\")\n rules.push(\"Lead with the action or answer, skip preamble\")\n break\n\n case \"gitlab\":\n lines.push(`From: ${input.sender}`)\n rules.push(\"Reply as a short, actionable GitLab comment — 3-5 lines for the main message\")\n rules.push(\"Do NOT mention Telegram handles — they don't work on GitLab\")\n rules.push(\"Do NOT delegate to other agents\")\n rules.push(\"Reference issues with #IID and merge requests with !IID\")\n rules.push(\"Put verbose details (logs, full commands, step-by-step) inside collapsible sections: <details><summary>Title</summary>\\\\n\\\\ncontent\\\\n</details>\")\n rules.push(\"Never narrate what you are about to do — just do it and report the result\")\n tags.push(\"code-review\")\n break\n\n case \"discord\":\n lines.push(`From: ${input.sender}`)\n rules.push(\"Use Discord markdown for formatting\")\n rules.push(\"Be brief — 2-4 sentences for the main point\")\n break\n\n default:\n if (input.channel.startsWith(\"webhook:\")) {\n rules.push(\"This is an automated event — respond with actionable steps\")\n tags.push(\"webhook\", \"automated\")\n }\n }\n\n if (rules.length) {\n lines.push(\"\")\n lines.push(\"[Rules]\")\n lines.push(...rules.map(r => `- ${r}`))\n }\n\n return { name: \"channel\", priority: 1, maxTokens, content: lines.join(\"\\n\"), tags, rules }\n}\n\n/**\n * Build scope context (group/personal/project).\n */\nfunction buildScopeLayer(input: ContextInput, maxTokens: number): ContextLayer {\n const lines: string[] = []\n const tags: string[] = []\n\n if (input.channelScope === \"group\" && input.groupName) {\n lines.push(`Group: ${input.groupName}`)\n tags.push(\"group\", input.groupName)\n } else if (input.channelScope === \"project\" && input.projectPath) {\n lines.push(`Project: ${input.projectPath}`)\n tags.push(\"project\", input.projectPath)\n } else if (input.channelScope === \"personal\") {\n lines.push(\"Direct message\")\n tags.push(\"dm\")\n }\n\n // Inject verified channel metadata (prevents hallucination)\n if (input.channelMeta) {\n const meta = input.channelMeta\n if (meta.agents?.length) {\n lines.push(`[Verified bots in this chat: ${meta.agents.map(a => a.handle || a.name || a.id).join(\", \")}]`)\n lines.push(\"Only mention these agents as group members — do NOT assume others are present.\")\n }\n if (meta.project) {\n lines.push(`Project: ${meta.project}`)\n }\n if (meta.issue) {\n lines.push(`${meta.issue.type} #${meta.issue.iid}${meta.issue.title ? `: ${meta.issue.title}` : \"\"}`)\n }\n if (meta.facts?.length) {\n for (const fact of meta.facts) {\n lines.push(`• ${fact}`)\n }\n }\n }\n\n return { name: \"scope\", priority: 2, maxTokens, content: lines.join(\"\\n\"), tags }\n}\n\n/**\n * Extract intent tags from message (lightweight, no LLM).\n */\nfunction extractIntentTags(message: string): string[] {\n const tags: string[] = []\n const lower = message.toLowerCase()\n\n // Action intents\n if (/deploy|push|release|ship/.test(lower)) tags.push(\"deployment\")\n if (/review|check|look at|approve/.test(lower)) tags.push(\"review\")\n if (/fix|bug|broken|error|issue/.test(lower)) tags.push(\"bugfix\")\n if (/create|add|build|implement/.test(lower)) tags.push(\"feature\")\n if (/test|spec|coverage/.test(lower)) tags.push(\"testing\")\n if (/refactor|clean|improve/.test(lower)) tags.push(\"refactor\")\n if (/docs|document|readme/.test(lower)) tags.push(\"docs\")\n if (/security|vuln|auth|token/.test(lower)) tags.push(\"security\")\n if (/perf|slow|optim|fast/.test(lower)) tags.push(\"performance\")\n if (/status|update|progress|standup/.test(lower)) tags.push(\"status\")\n if (/help|how|what|explain/.test(lower)) tags.push(\"question\")\n\n // Domain intents\n if (/gitlab|merge|mr|issue|pipeline/.test(lower)) tags.push(\"gitlab\")\n if (/seo|analytics|content|marketing/.test(lower)) tags.push(\"marketing\")\n if (/infra|server|docker|k8s|devops/.test(lower)) tags.push(\"devops\")\n\n return tags\n}\n\n/**\n * Estimate token count from text.\n */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / CHARS_PER_TOKEN)\n}\n","import { readFileSync, writeFileSync, appendFileSync, mkdirSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { buildIndex, scoreAll } from \"../memory/bm25\"\n\n// --- Persistent agent memory store ---\n// JSONL-based. One file per agent: .agentx/memory/{agentId}.jsonl\n// Extracted by Haiku post-conversation, injected pre-conversation.\n\nexport interface MemoryFact {\n id: string\n agentId: string\n category: \"fact\" | \"secret\" | \"preference\" | \"commitment\" | \"task-state\"\n content: string\n keywords: string[]\n source: { channel: string; chatId: string; sender: string; date: string }\n createdAt: string\n expiresAt?: string\n}\n\nconst MAX_MEMORIES = 200\nconst TASK_STATE_TTL_DAYS = 7\n\n\nexport class MemoryStore {\n private memoryDir: string\n\n constructor(baseDir: string = process.cwd()) {\n this.memoryDir = resolve(baseDir, \".agentx/memory\")\n if (!existsSync(this.memoryDir)) {\n mkdirSync(this.memoryDir, { recursive: true })\n }\n }\n\n private filePath(agentId: string): string {\n return resolve(this.memoryDir, `${agentId}.jsonl`)\n }\n\n addMemory(agentId: string, fact: Omit<MemoryFact, \"id\" | \"createdAt\">): void {\n const entry: MemoryFact = {\n ...fact,\n id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`,\n createdAt: new Date().toISOString(),\n }\n appendFileSync(this.filePath(agentId), JSON.stringify(entry) + \"\\n\")\n }\n\n getAll(agentId: string): MemoryFact[] {\n const file = this.filePath(agentId)\n if (!existsSync(file)) return []\n\n try {\n const lines = readFileSync(file, \"utf-8\").split(\"\\n\").filter(l => l.trim())\n return lines.map(l => {\n try { return JSON.parse(l) as MemoryFact } catch { return null }\n }).filter((m): m is MemoryFact => m !== null)\n } catch {\n return []\n }\n }\n\n findRelevant(message: string, agentId: string, limit: number = 8): MemoryFact[] {\n const memories = this.getAll(agentId)\n if (memories.length === 0) return []\n\n // BM25 over keywords + content\n const docs = memories.map((m) => `${m.keywords.join(\" \")} ${m.content}`)\n const index = buildIndex(docs)\n const bm25Scores = scoreAll(message, index)\n const scoreMap = new Map(bm25Scores.map((r) => [r.docIndex, r.score]))\n\n const scored = memories.map((m, i) => {\n let s = scoreMap.get(i) ?? 0\n // Category boosts (preserved from original)\n if (m.category === \"secret\") s += 2\n if (m.category === \"commitment\") s += 1\n return { memory: m, score: s }\n })\n\n const matched = scored.filter((s) => s.score > 0)\n if (matched.length === 0) return memories.slice(-limit) // fallback: recent\n\n return matched\n .sort((a, b) => b.score - a.score)\n .slice(0, limit)\n .map((s) => s.memory)\n }\n\n buildContext(memories: MemoryFact[]): string {\n if (memories.length === 0) return \"\"\n\n const lines = [\"[Agent Memory — persistent facts from past conversations]\"]\n let chars = lines[0].length\n\n for (const m of memories) {\n const isDM = !m.source.chatId.startsWith(\"-\") && /^\\d+$/.test(m.source.chatId)\n const scope = isDM ? \"DM\" : m.source.chatId\n const line = `- [${m.category}] ${m.content} (${scope}, ${m.source.date})`\n\n if (chars + line.length > 2400) break\n lines.push(line)\n chars += line.length\n }\n\n lines.push(\"[End Memory]\")\n return lines.join(\"\\n\")\n }\n\n /**\n * Check if a substantially similar memory already exists.\n */\n hasSimilar(agentId: string, content: string): boolean {\n const memories = this.getAll(agentId)\n const contentLower = content.toLowerCase()\n const contentWords = contentLower.split(/\\s+/).filter(w => w.length > 3)\n\n return memories.some(m => {\n const mLower = m.content.toLowerCase()\n // Check for high word overlap\n const overlap = contentWords.filter(w => mLower.includes(w)).length\n return overlap >= contentWords.length * 0.7\n })\n }\n\n /**\n * Prune old/expired memories. Cap at MAX_MEMORIES per agent.\n */\n prune(agentId: string): void {\n let memories = this.getAll(agentId)\n if (memories.length === 0) return\n\n const now = Date.now()\n const ttlMs = TASK_STATE_TTL_DAYS * 24 * 60 * 60 * 1000\n\n // Remove expired task-state memories\n memories = memories.filter(m => {\n if (m.category === \"task-state\" && m.expiresAt) {\n return new Date(m.expiresAt).getTime() > now\n }\n if (m.category === \"task-state\" && !m.expiresAt) {\n return now - new Date(m.createdAt).getTime() < ttlMs\n }\n return true\n })\n\n // Cap at MAX_MEMORIES (keep most recent)\n if (memories.length > MAX_MEMORIES) {\n memories = memories.slice(-MAX_MEMORIES)\n }\n\n // Rewrite file\n const file = this.filePath(agentId)\n writeFileSync(file, memories.map(m => JSON.stringify(m)).join(\"\\n\") + \"\\n\")\n }\n}\n","// --- Message Queue with Modes ---\n//\n// Handles messages arriving while an agent is busy processing.\n// Prevents duplicate runs, lost messages, and race conditions.\n//\n// Modes:\n// collect — batch messages arriving during a run, deliver all at once when done\n// followup — queue each message as a separate follow-up turn after current run\n// drop — silently discard messages while busy (for non-critical channels)\n\nexport type QueueMode = \"collect\" | \"followup\" | \"drop\"\n\nexport interface QueuedMessage {\n text: string\n sender: string\n timestamp: number\n channel: string\n chatId: string\n /** Full context from the original message, preserved for re-routing */\n originalContext?: Record<string, unknown>\n}\n\ninterface SessionQueue {\n mode: QueueMode\n /** Messages waiting to be processed */\n pending: QueuedMessage[]\n /** Whether an agent run is currently in progress for this session */\n running: boolean\n /** Callback to invoke when a queued message should be processed */\n onFlush?: (messages: QueuedMessage[]) => Promise<void>\n}\n\n/**\n * Per-agent, per-session message queue.\n * Keyed by `agentId:channel:chatId`.\n */\nexport class MessageQueue {\n private queues: Map<string, SessionQueue> = new Map()\n private defaultMode: QueueMode\n\n constructor(defaultMode: QueueMode = \"collect\") {\n this.defaultMode = defaultMode\n }\n\n private key(agentId: string, channel: string, chatId: string): string {\n return `${agentId}:${channel}:${chatId}`\n }\n\n private getOrCreate(agentId: string, channel: string, chatId: string): SessionQueue {\n const k = this.key(agentId, channel, chatId)\n if (!this.queues.has(k)) {\n this.queues.set(k, {\n mode: this.defaultMode,\n pending: [],\n running: false,\n })\n }\n return this.queues.get(k)!\n }\n\n /**\n * Set the queue mode for a specific session.\n */\n setMode(agentId: string, channel: string, chatId: string, mode: QueueMode): void {\n this.getOrCreate(agentId, channel, chatId).mode = mode\n }\n\n /**\n * Register a flush callback for when queued messages should be processed.\n */\n onFlush(\n agentId: string,\n channel: string,\n chatId: string,\n callback: (messages: QueuedMessage[]) => Promise<void>,\n ): void {\n this.getOrCreate(agentId, channel, chatId).onFlush = callback\n }\n\n /**\n * Check if an agent is currently busy for a given session.\n */\n isBusy(agentId: string, channel: string, chatId: string): boolean {\n return this.getOrCreate(agentId, channel, chatId).running\n }\n\n /**\n * Mark the start of an agent run. Returns false if already running.\n */\n markRunning(agentId: string, channel: string, chatId: string): boolean {\n const q = this.getOrCreate(agentId, channel, chatId)\n if (q.running) return false\n q.running = true\n return true\n }\n\n /**\n * Enqueue a message that arrived while the agent is busy.\n * Returns the queue mode applied (or null if not busy and no queueing needed).\n */\n enqueue(\n agentId: string,\n channel: string,\n chatId: string,\n message: QueuedMessage,\n ): QueueMode | null {\n const q = this.getOrCreate(agentId, channel, chatId)\n\n if (!q.running) return null // Not busy, process normally\n\n switch (q.mode) {\n case \"drop\":\n return \"drop\"\n\n case \"collect\":\n case \"followup\":\n q.pending.push(message)\n return q.mode\n }\n }\n\n /**\n * Mark the end of an agent run. Flushes pending messages based on mode.\n * Returns messages to process (if any).\n */\n async markDone(\n agentId: string,\n channel: string,\n chatId: string,\n ): Promise<QueuedMessage[]> {\n const q = this.getOrCreate(agentId, channel, chatId)\n q.running = false\n\n if (q.pending.length === 0) return []\n\n const messages = [...q.pending]\n q.pending = []\n\n switch (q.mode) {\n case \"collect\": {\n // Batch all pending messages into a single combined message\n const combined: QueuedMessage = {\n text: messages.map((m) =>\n `[${m.sender}, ${new Date(m.timestamp).toISOString().slice(11, 16)}]: ${m.text}`\n ).join(\"\\n\"),\n sender: messages[messages.length - 1].sender,\n timestamp: Date.now(),\n channel: messages[0].channel,\n chatId: messages[0].chatId,\n originalContext: messages[messages.length - 1].originalContext,\n }\n\n // Fire flush callback with combined message\n if (q.onFlush) {\n await q.onFlush([combined])\n }\n return [combined]\n }\n\n case \"followup\":\n // Process each message as a separate follow-up turn\n if (q.onFlush) {\n await q.onFlush(messages)\n }\n return messages\n\n case \"drop\":\n return []\n\n default:\n return messages\n }\n }\n\n /**\n * Get the number of pending messages for a session.\n */\n pendingCount(agentId: string, channel: string, chatId: string): number {\n return this.getOrCreate(agentId, channel, chatId).pending.length\n }\n\n /**\n * Clear all queued messages for a session (e.g., on session reset).\n */\n clear(agentId: string, channel: string, chatId: string): void {\n const k = this.key(agentId, channel, chatId)\n this.queues.delete(k)\n }\n\n /**\n * Get queue stats for monitoring.\n */\n stats(): Array<{ key: string; mode: QueueMode; pending: number; running: boolean }> {\n return Array.from(this.queues.entries()).map(([key, q]) => ({\n key,\n mode: q.mode,\n pending: q.pending.length,\n running: q.running,\n }))\n }\n}\n","import { readFileSync, existsSync, unlinkSync } from \"fs\"\nimport { resolve } from \"path\"\n\n// --- Bootstrap Identity Files ---\n//\n// Support for structured workspace identity files (inspired by OpenClaw).\n// These files live in the agent's workspace and are auto-loaded into context.\n//\n// Supported files:\n// SOUL.md — personality, tone, boundaries (persistent)\n// IDENTITY.md — name, role, emoji, tagline (persistent)\n// USER.md — user profile, preferences (persistent)\n// AGENTS.md — operating rules, standing orders (persistent)\n// BOOTSTRAP.md — one-time first-run ritual (auto-deleted after first load)\n\nexport interface BootstrapFiles {\n soul?: string\n identity?: string\n user?: string\n agents?: string\n bootstrap?: string\n}\n\nconst BOOTSTRAP_FILE_NAMES = [\n \"SOUL.md\",\n \"IDENTITY.md\",\n \"USER.md\",\n \"AGENTS.md\",\n \"BOOTSTRAP.md\",\n] as const\n\n/**\n * Load bootstrap identity files from an agent's workspace.\n * Returns content keyed by file type. Missing files are omitted.\n */\nexport function loadBootstrapFiles(workspace: string): BootstrapFiles {\n const result: BootstrapFiles = {}\n\n const tryLoad = (filename: string): string | undefined => {\n const filePath = resolve(workspace, filename)\n if (!existsSync(filePath)) return undefined\n try {\n const content = readFileSync(filePath, \"utf-8\").trim()\n return content || undefined\n } catch {\n return undefined\n }\n }\n\n result.soul = tryLoad(\"SOUL.md\")\n result.identity = tryLoad(\"IDENTITY.md\")\n result.user = tryLoad(\"USER.md\")\n result.agents = tryLoad(\"AGENTS.md\")\n result.bootstrap = tryLoad(\"BOOTSTRAP.md\")\n\n // BOOTSTRAP.md is one-time: delete after loading\n if (result.bootstrap) {\n try {\n unlinkSync(resolve(workspace, \"BOOTSTRAP.md\"))\n } catch {\n // Best-effort deletion\n }\n }\n\n return result\n}\n\n/**\n * Build context string from bootstrap files.\n * Returns empty string if no files found.\n */\nexport function buildBootstrapContext(files: BootstrapFiles): string {\n const sections: string[] = []\n\n if (files.identity) {\n sections.push(`[Identity]\\n${files.identity}`)\n }\n\n if (files.soul) {\n sections.push(`[Personality & Boundaries]\\n${files.soul}`)\n }\n\n if (files.agents) {\n sections.push(`[Operating Rules]\\n${files.agents}`)\n }\n\n if (files.user) {\n sections.push(`[User Profile]\\n${files.user}`)\n }\n\n if (files.bootstrap) {\n sections.push(`[First-Run Instructions — one time only]\\n${files.bootstrap}`)\n }\n\n if (sections.length === 0) return \"\"\n\n return sections.join(\"\\n\\n\")\n}\n\n/**\n * Check which bootstrap files exist in a workspace (for status/diagnostics).\n */\nexport function listBootstrapFiles(workspace: string): string[] {\n return BOOTSTRAP_FILE_NAMES.filter((name) =>\n existsSync(resolve(workspace, name))\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 { WikiHub } from \"@/wiki\"\nimport { RateLimiter } from \"@/daemon/rate-limit\"\nimport { TokenTracker } from \"@/daemon/token-tracker\"\nimport { buildAgentContext, type ContextInput } from \"./context\"\nimport { MemoryStore } from \"./memory-store\"\nimport { extractMemories } from \"./memory-extract\"\nimport { MessageQueue, type QueueMode, type QueuedMessage } from \"./message-queue\"\nimport { loadBootstrapFiles, buildBootstrapContext } from \"./bootstrap\"\nimport type { LandscapeBuilder } from \"./landscape\"\n\n// --- Agent Registry: lifecycle management + concurrency control ---\n\n/** Global singleton for sub-agent spawning from tools */\nlet globalRegistry: AgentRegistry | undefined\n\nexport function setGlobalRegistry(registry: AgentRegistry): void {\n globalRegistry = registry\n}\n\nexport function getGlobalRegistry(): AgentRegistry | undefined {\n return globalRegistry\n}\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 wikiHub: WikiHub\n private memoryStore: MemoryStore\n private rateLimiter: RateLimiter\n private tokenTracker: TokenTracker\n private landscape?: LandscapeBuilder\n private messageQueue: MessageQueue\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.wikiHub = new WikiHub(undefined, undefined, \"unified\")\n this.memoryStore = new MemoryStore()\n this.rateLimiter = new RateLimiter()\n this.tokenTracker = new TokenTracker()\n this.messageQueue = new MessageQueue()\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 * Set landscape builder (called after mesh init).\n */\n setLandscape(builder: LandscapeBuilder): void {\n this.landscape = builder\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., \"@my_bot\" -> \"my-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 /** Wiki hub accessor. */\n getWikiHub(): WikiHub { return this.wikiHub }\n\n /**\n * Build peer list for context engine.\n */\n private buildPeerList(agentId: string, channel?: string): Array<{ name: string; handle?: string; role?: string }> {\n const peers: Array<{ name: string; handle?: string; role?: string }> = []\n for (const [id, state] of this.agents) {\n if (id === agentId) continue\n peers.push({\n name: state.def.name,\n handle: this.getChannelHandle(id, channel),\n role: state.def.systemPrompt?.split(\"\\n\")[0]?.slice(0, 80),\n })\n }\n return peers\n }\n\n /**\n * Get the primary channel handle for an agent (e.g. \"@my_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 * 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 // Build session key for queue management\n const qChannel = task.context?.channel || \"api\"\n const qChatId = task.context?.chatId || task.context?.group || task.context?.sender || \"default\"\n\n if (state.activeTasks >= state.def.maxConcurrent) {\n // Agent is busy — try to queue the message instead of rejecting\n const mode = (state.def.queueMode as QueueMode) || \"collect\"\n const queued = this.messageQueue.enqueue(task.agentId, qChannel, qChatId, {\n text: task.message,\n sender: task.context?.sender || \"User\",\n timestamp: Date.now(),\n channel: qChannel,\n chatId: qChatId,\n originalContext: task.context as Record<string, unknown>,\n })\n\n if (queued === \"drop\") {\n this.log(`[${task.agentId}] busy, message dropped (mode: drop)`)\n return { content: \"\", error: `Agent \"${task.agentId}\" is busy — message dropped` }\n }\n\n if (queued) {\n const pending = this.messageQueue.pendingCount(task.agentId, qChannel, qChatId)\n this.log(`[${task.agentId}] busy, message queued (mode: ${queued}, pending: ${pending})`)\n return {\n content: \"\",\n error: `__queued__:${queued}:${pending}`,\n }\n }\n }\n\n // Rate limit check\n const rateCheck = this.rateLimiter.check(task.agentId)\n if (!rateCheck.allowed) {\n this.log(`[${task.agentId}] ${rateCheck.reason}`)\n return { content: \"\", error: rateCheck.reason }\n }\n\n state.activeTasks++\n state.totalTasks++\n state.lastActive = new Date()\n\n // Mark session as running in the message queue\n this.messageQueue.markRunning(task.agentId, qChannel, qChatId)\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?.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 // Build structured context — read from per-agent wiki\n const agentWiki = this.wikiHub.getAgentWiki(task.agentId)\n const wikiArticles = agentWiki.findRelevant(task.message, task.agentId, 3)\n const wikiContext = agentWiki.buildContext(wikiArticles)\n\n // Load persistent agent memory (cross-session facts)\n const relevantMemories = this.memoryStore.findRelevant(task.message, task.agentId, 8)\n const memoryContext = this.memoryStore.buildContext(relevantMemories)\n\n // Decide whether to resume or start fresh\n let resumeSessionId = state.def.tier === \"claude-code\"\n ? this.sessions.getClaudeSessionId(task.agentId, channel, chatId)\n : undefined\n\n // If session is stale (idle > 15min), start fresh with full context rebuild\n if (resumeSessionId && this.sessions.isSessionStale(task.agentId, channel, chatId)) {\n this.log(`[${task.agentId}] session stale for ${channel}:${chatId}, starting fresh`)\n this.sessions.clearClaudeSessionId(task.agentId, channel, chatId)\n resumeSessionId = undefined\n }\n\n // Compact session if history is getting too long (summarize older messages)\n try {\n const compacted = await this.sessions.compactIfNeeded(\n task.agentId, channel, chatId, this.memoryStore,\n )\n if (compacted) {\n this.log(`[${task.agentId}] session compacted for ${channel}:${chatId}`)\n resumeSessionId = undefined\n }\n } catch (e: any) {\n this.log(`[${task.agentId}] compaction failed (non-fatal): ${e.message}`)\n }\n\n const sessionHistory = !resumeSessionId\n ? this.sessions.buildHistoryContext(task.agentId, channel, chatId)\n : undefined\n\n // Bridge cross-chat amnesia: inject context from other chats (DM ↔ group)\n const crossChatContext = this.sessions.getCrossSessionSummary(task.agentId, channel, chatId)\n\n // Load bootstrap identity files (SOUL.md, IDENTITY.md, etc.) from workspace\n const bootstrapFiles = loadBootstrapFiles(state.def.workspace)\n const bootstrapContext = buildBootstrapContext(bootstrapFiles)\n\n const contextInput: ContextInput = {\n channel,\n channelScope: task.context?.group ? \"group\" : (channel === \"gitlab\" ? \"project\" : \"personal\"),\n groupName: task.context?.group,\n agentId: task.agentId,\n agentName: state.def.name,\n agentHandle: this.getChannelHandle(task.agentId, channel),\n systemPrompt: state.def.systemPrompt,\n sender: senderName,\n senderId: task.context?.senderId,\n senderUsername: task.context?.senderUsername,\n landscape: this.landscape?.getForAgent(task.agentId),\n channelMeta: task.context?.channelMeta,\n mediaPath: task.context?.mediaPath,\n mediaType: task.context?.mediaType,\n replyToText: task.context?.replyToText,\n bootstrapContext: bootstrapContext || undefined,\n groupHistory: task.context?.group ? undefined : undefined, // group log is injected by router\n sessionHistory,\n memoryContext: memoryContext || undefined,\n crossChatContext: crossChatContext || undefined,\n wikiContext,\n message: task.message,\n }\n\n const historyContext = buildAgentContext(contextInput)\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.wikiHub.getSharedStore().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 // Memory: extract and store memorable facts via Haiku (fire-and-forget)\n extractMemories(\n task.agentId,\n task.message,\n response.content,\n { channel, chatId, sender: senderName },\n this.memoryStore,\n ).catch(() => {})\n }\n\n // Track token usage (real counts if available, estimate otherwise)\n this.tokenTracker.record(\n task.agentId,\n response.duration || 0,\n response.usage,\n task.message.length,\n response.content.length,\n false,\n state.def.model,\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 // Flush queued messages that arrived while this run was in progress\n this.messageQueue.markDone(task.agentId, qChannel, qChatId)\n .then((queued) => {\n if (queued.length === 0) return\n this.log(`[${task.agentId}] flushing ${queued.length} queued message(s)`)\n // Re-execute each queued message as a new task\n for (const qm of queued) {\n this.execute({\n message: qm.text,\n agentId: task.agentId,\n context: (qm.originalContext as AgentTask[\"context\"]) || {\n channel: qm.channel,\n sender: qm.sender,\n chatId: qm.chatId,\n },\n }).catch((e) => {\n this.log(`[${task.agentId}] queued message failed: ${e.message}`)\n })\n }\n })\n .catch((e) => {\n this.log(`[${task.agentId}] queue flush failed: ${e.message}`)\n })\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 /**\n * Get token usage summary.\n */\n getUsage(days: number = 7) {\n return this.tokenTracker.summary(days)\n }\n\n /**\n * Get today's usage.\n */\n getTodayUsage() {\n return this.tokenTracker.today()\n }\n\n /**\n * Get the token tracker instance (for daemon hooks).\n */\n getTokenTracker(): TokenTracker {\n return this.tokenTracker\n }\n}\n"],"mappings":"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","names":["execa","execFile","buildPrompt","agent","task","historyContext","parts","ctx","envLines","isGitLab","isTelegram","peer","handle","role","buildClaudeArgs","prompt","streaming","resumeSessionId","args","parseClaudeJsonOutput","stdout","data","usage","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","mkdirSync","existsSync","readdirSync","resolve","MAX_HISTORY_CHARS","MAX_MESSAGES","STALE_SESSION_MINUTES","COMPACTION_MARKER","SessionStore","baseDir","agentId","channel","chatId","day","key","safe","file","data","session","senderName","content","claudeSessionId","lines","msg","time","currentKey","files","f","hints","recent","scope","m","memoryStore","needsCompaction","compactSession","applyCompaction","result","totalChars","sum","removed","readFileSync","writeFileSync","appendFileSync","existsSync","mkdirSync","readdirSync","statSync","resolve","join","relative","dirname","WikiStore","baseDir","resolve","log","mkdirSync","article","agentId","entry","filename","filepath","frontmatter","k","v","writeFileSync","filter","existsSync","files","readdirSync","f","entries","file","content","readFileSync","fmMatch","fm","body","get","key","path","meta","existing","fullPath","dirname","t","s","action","raw","getArray","m","tags","i","a","articles","filePath","relPath","relative","query","maxResults","queryLower","docs","index","buildIndex","bm25Scores","scoreAll","scoreMap","r","score","b","message","maxArticles","maxChars","lines","totalChars","header","chunk","backlinks","links","link","target","aliases","md","byType","type","list","x","y","access","totalArticles","byAccess","byOwner","tag","entryFiles","details","logPath","appendFileSync","limit","e","schemaPath","title","lowerTags","results","articleTags","sectionTags","allTags","tagCounts","issues","allTitles","allLinks","articlePaths","articlePath","allSources","maxEntries","unabsorbed","entrySummaries","dir","callback","full","join","statSync","resolve","existsSync","readdirSync","mkdirSync","WikiHub","baseDir","log","mode","WikiStore","agentId","key","agentDir","store","agents","entries","e","dir","agentWiki","agentEntries","absorbedIds","index","article","s","unabsorbed","RateLimiter","maxPerMinute","maxPerHour","agentId","now","timestamps","hourAgo","recent","t","minuteAgo","lastMinute","DEFAULT_CONFIG","CHARS_PER_TOKEN","buildAgentContext","input","config","layers","buildLayers","a","b","parts","totalChars","maxChars","layer","layerMaxChars","trimmed","remaining","budget","name","fallback","buildChannelLayer","buildScopeLayer","intentTags","extractIntentTags","artifactLines","history","maxTokens","lines","rules","tags","meta","fact","message","lower","readFileSync","writeFileSync","appendFileSync","mkdirSync","existsSync","resolve","MAX_MEMORIES","TASK_STATE_TTL_DAYS","MemoryStore","baseDir","resolve","existsSync","mkdirSync","agentId","fact","entry","appendFileSync","file","readFileSync","l","m","message","limit","memories","docs","index","buildIndex","bm25Scores","scoreAll","scoreMap","r","matched","i","s","a","b","lines","chars","scope","line","content","contentWords","w","mLower","now","ttlMs","writeFileSync","MessageQueue","defaultMode","agentId","channel","chatId","k","mode","callback","q","message","messages","combined","m","key","readFileSync","existsSync","unlinkSync","resolve","loadBootstrapFiles","workspace","result","tryLoad","filename","filePath","resolve","existsSync","readFileSync","unlinkSync","buildBootstrapContext","files","sections","globalRegistry","setGlobalRegistry","registry","getGlobalRegistry","AgentRegistry","config","log","SessionStore","WikiHub","MemoryStore","RateLimiter","TokenTracker","MessageQueue","id","def","builder","text","lower","bestId","bestLen","state","mention","mentionLower","found","agentId","channel","peers","agent","m","task","onDelta","qChannel","qChatId","mode","queued","pending","rateCheck","chatId","senderName","agentWiki","wikiArticles","wikiContext","relevantMemories","memoryContext","resumeSessionId","e","sessionHistory","crossChatContext","bootstrapFiles","loadBootstrapFiles","bootstrapContext","buildBootstrapContext","contextInput","historyContext","buildAgentContext","response","executeTask","entryId","extractMemories","error","qm","s","days"]}
@@ -1,46 +1,46 @@
1
- import{b as P,d as I}from"./chunk-M7HKBG3V.js";var M=[{name:"create_files",description:"Create one or more files as output. Use this when you need to generate code, documents, configs, or any file-based output.",input_schema:{type:"object",properties:{files:{type:"array",items:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root (e.g., src/components/Button.tsx)"},content:{type:"string",description:"The full content of the file"},language:{type:"string",description:"Programming language or file type"},description:{type:"string",description:"Brief description of what this file does"}},required:["path","content"]}},summary:{type:"string",description:"Brief summary of all generated files"}},required:["files"]},permission:"file-write"},{name:"ask_user",description:"Ask the user a clarifying question when you need more information to proceed. Use this when the request is ambiguous or you need to confirm important decisions.",input_schema:{type:"object",properties:{question:{type:"string",description:"The question to ask the user"},options:{type:"array",items:{type:"string"},description:"Optional list of choices for the user"}},required:["question"]},permission:"none"},{name:"read_file",description:"Read the contents of a file. Use this to inspect existing code, understand patterns, check implementations, or gather context before generating code.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root"},max_lines:{type:"number",description:"Maximum number of lines to read. Defaults to 500. Use for large files."}},required:["path"]},permission:"file-read"},{name:"search_files",description:"Search for files matching a pattern and optionally search their content with a regex. Use this to find relevant code, understand project structure, or locate specific patterns.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Glob pattern to match files (e.g., 'src/**/*.ts', '*.json')"},content_regex:{type:"string",description:"Optional regex to search within matched files. Returns matching lines."},max_results:{type:"number",description:"Maximum number of results to return. Default: 50."}},required:["pattern"]},permission:"none"},{name:"list_directory",description:"List files and directories at a given path. Use this to explore project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative directory path from project root. Defaults to '.' (root)."},recursive:{type:"boolean",description:"List recursively. Default: false."},max_depth:{type:"number",description:"Maximum depth for recursive listing. Default: 3."}}},permission:"none"},{name:"run_command",description:"Execute a shell command. Use this to run build tools, test commands, linters, or inspect the environment. Commands run in the project root directory.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute"},timeout:{type:"number",description:"Timeout in milliseconds. Default: 30000 (30 seconds)."}},required:["command"]},permission:"command"},{name:"edit_file",description:"Apply search-and-replace edits to an existing file. Use this for targeted modifications to existing code rather than rewriting entire files.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root"},edits:{type:"array",items:{type:"object",properties:{old_text:{type:"string",description:"The exact text to find in the file"},new_text:{type:"string",description:"The replacement text"}},required:["old_text","new_text"]},description:"List of search/replace pairs to apply in order"}},required:["path","edits"]},permission:"file-write"}];function K(A){return(A?M.filter(e=>A.includes(e.name)):M).map(({name:e,description:i,input_schema:s})=>({name:e,description:i,input_schema:s}))}function j(){return K(["create_files","ask_user"])}function B(){let A=M.filter(e=>e.name!=="create_files"&&e.name!=="ask_user");if(A.length===0)return"";let t=["# Available Capabilities","In addition to generating files, you have the following capabilities:",""];for(let e of A)t.push(`## ${e.name}`),t.push(e.description),t.push("");return t.join(`
2
- `)}var H=M.map(A=>A.name);var U="claude-sonnet-4-20250514",L=8192,C=class{name="claude";apiKey;authType="api-key";constructor(t){if(this.apiKey=t||process.env.ANTHROPIC_API_KEY||"",!this.apiKey){let e=I();e&&(this.apiKey=e.token,this.authType=e.authType)}if(!this.apiKey)throw new Error("Anthropic API key required. Run `agentx model` to configure, set ANTHROPIC_API_KEY, or pass --api-key.")}async generate(t,e){let i=e?.model||U,s=e?.maxTokens||L,r=t.find(p=>p.role==="system"),u=t.filter(p=>p.role!=="system").map(p=>({role:p.role,content:p.content})),g={model:i,max_tokens:s,messages:u,tools:j()};r&&(g.system=r.content),e?.temperature!==void 0&&(g.temperature=e.temperature);let h=await this.callApi(g);return this.parseResponse(h)}async generateRaw(t,e,i,s){let r=s?.model||U,u=s?.maxTokens||L,g={model:r,max_tokens:u,system:e,messages:t,tools:i};s?.temperature!==void 0&&(g.temperature=s.temperature);let h=await this.callApi(g);return{content:h.content.map(c=>c.type==="text"?{type:"text",text:c.text||""}:c.type==="tool_use"?{type:"tool_use",id:c.id||"",name:c.name||"",input:c.input||{}}:{type:"text",text:""}),stop_reason:h.stop_reason,usage:h.usage}}async*stream(t,e){let i=e?.model||U,s=e?.maxTokens||L,r=t.find(m=>m.role==="system"),u=t.filter(m=>m.role!=="system").map(m=>({role:m.role,content:m.content})),g={model:i,max_tokens:s,messages:u,stream:!0,tools:j()};r&&(g.system=r.content);let h=this.buildHeaders(),p=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:h,body:JSON.stringify(g)});if(!p.ok){let m=await p.text();yield{type:"error",error:`Anthropic API error (${p.status}): ${m}`};return}let c=p.body?.getReader();if(!c){yield{type:"error",error:"No response body"};return}let d=new TextDecoder,a="",_=[],v="",x,k=0,n=null,y=m=>{let R=(m||"").trim();if(!R||R.includes("```"))return;let T=R.replace(/\r\n/g,`
1
+ import{b as j,d as M}from"./chunk-M7HKBG3V.js";var q=[{name:"create_files",description:"Create one or more files as output. Use this when you need to generate code, documents, configs, or any file-based output.",input_schema:{type:"object",properties:{files:{type:"array",items:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root (e.g., src/components/Button.tsx)"},content:{type:"string",description:"The full content of the file"},language:{type:"string",description:"Programming language or file type"},description:{type:"string",description:"Brief description of what this file does"}},required:["path","content"]}},summary:{type:"string",description:"Brief summary of all generated files"}},required:["files"]},permission:"file-write"},{name:"ask_user",description:"Ask the user a clarifying question when you need more information to proceed. Use this when the request is ambiguous or you need to confirm important decisions.",input_schema:{type:"object",properties:{question:{type:"string",description:"The question to ask the user"},options:{type:"array",items:{type:"string"},description:"Optional list of choices for the user"}},required:["question"]},permission:"none"},{name:"read_file",description:"Read the contents of a file. Use this to inspect existing code, understand patterns, check implementations, or gather context before generating code.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root"},max_lines:{type:"number",description:"Maximum number of lines to read. Defaults to 500. Use for large files."}},required:["path"]},permission:"file-read"},{name:"search_files",description:"Search for files matching a pattern and optionally search their content with a regex. Use this to find relevant code, understand project structure, or locate specific patterns.",input_schema:{type:"object",properties:{pattern:{type:"string",description:"Glob pattern to match files (e.g., 'src/**/*.ts', '*.json')"},content_regex:{type:"string",description:"Optional regex to search within matched files. Returns matching lines."},max_results:{type:"number",description:"Maximum number of results to return. Default: 50."}},required:["pattern"]},permission:"none"},{name:"list_directory",description:"List files and directories at a given path. Use this to explore project structure.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative directory path from project root. Defaults to '.' (root)."},recursive:{type:"boolean",description:"List recursively. Default: false."},max_depth:{type:"number",description:"Maximum depth for recursive listing. Default: 3."}}},permission:"none"},{name:"run_command",description:"Execute a shell command. Use this to run build tools, test commands, linters, or inspect the environment. Commands run in the project root directory.",input_schema:{type:"object",properties:{command:{type:"string",description:"The shell command to execute"},timeout:{type:"number",description:"Timeout in milliseconds. Default: 30000 (30 seconds)."}},required:["command"]},permission:"command"},{name:"edit_file",description:"Apply search-and-replace edits to an existing file. Use this for targeted modifications to existing code rather than rewriting entire files.",input_schema:{type:"object",properties:{path:{type:"string",description:"Relative file path from project root"},edits:{type:"array",items:{type:"object",properties:{old_text:{type:"string",description:"The exact text to find in the file"},new_text:{type:"string",description:"The replacement text"}},required:["old_text","new_text"]},description:"List of search/replace pairs to apply in order"}},required:["path","edits"]},permission:"file-write"},{name:"spawn_agent",description:"Spawn a sub-agent to handle a task in the background. The sub-agent runs in its own session and returns results. Use this for parallel research, long-running tasks, or delegating work to a specialized agent.",input_schema:{type:"object",properties:{agent_id:{type:"string",description:"The ID of the agent to spawn (must be a registered agent)"},prompt:{type:"string",description:"The task description for the sub-agent"},timeout_seconds:{type:"number",description:"Maximum time to wait for completion in seconds. Default: 300 (5 minutes)."}},required:["agent_id","prompt"]},permission:"none"}];function K(A){return(A?q.filter(e=>A.includes(e.name)):q).map(({name:e,description:i,input_schema:o})=>({name:e,description:i,input_schema:o}))}function P(){return K(["create_files","ask_user"])}function B(){let A=q.filter(e=>e.name!=="create_files"&&e.name!=="ask_user");if(A.length===0)return"";let t=["# Available Capabilities","In addition to generating files, you have the following capabilities:",""];for(let e of A)t.push(`## ${e.name}`),t.push(e.description),t.push("");return t.join(`
2
+ `)}var H=q.map(A=>A.name);var U="claude-sonnet-4-20250514",L=8192,C=class{name="claude";apiKey;authType="api-key";constructor(t){if(this.apiKey=t||process.env.ANTHROPIC_API_KEY||"",!this.apiKey){let e=M();e&&(this.apiKey=e.token,this.authType=e.authType)}if(!this.apiKey)throw new Error("Anthropic API key required. Run `agentx model` to configure, set ANTHROPIC_API_KEY, or pass --api-key.")}async generate(t,e){let i=e?.model||U,o=e?.maxTokens||L,r=t.find(p=>p.role==="system"),u=t.filter(p=>p.role!=="system").map(p=>({role:p.role,content:p.content})),g={model:i,max_tokens:o,messages:u,tools:P()};r&&(g.system=r.content),e?.temperature!==void 0&&(g.temperature=e.temperature);let h=await this.callApi(g);return this.parseResponse(h)}async generateRaw(t,e,i,o){let r=o?.model||U,u=o?.maxTokens||L,g={model:r,max_tokens:u,system:e,messages:t,tools:i};o?.temperature!==void 0&&(g.temperature=o.temperature);let h=await this.callApi(g);return{content:h.content.map(c=>c.type==="text"?{type:"text",text:c.text||""}:c.type==="tool_use"?{type:"tool_use",id:c.id||"",name:c.name||"",input:c.input||{}}:{type:"text",text:""}),stop_reason:h.stop_reason,usage:h.usage}}async*stream(t,e){let i=e?.model||U,o=e?.maxTokens||L,r=t.find(m=>m.role==="system"),u=t.filter(m=>m.role!=="system").map(m=>({role:m.role,content:m.content})),g={model:i,max_tokens:o,messages:u,stream:!0,tools:P()};r&&(g.system=r.content);let h=this.buildHeaders(),p=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:h,body:JSON.stringify(g)});if(!p.ok){let m=await p.text();yield{type:"error",error:`Anthropic API error (${p.status}): ${m}`};return}let c=p.body?.getReader();if(!c){yield{type:"error",error:"No response body"};return}let d=new TextDecoder,a="",_=[],v="",x,k=0,n=null,y=m=>{let R=(m||"").trim();if(!R||R.includes("```"))return;let b=R.replace(/\r\n/g,`
3
3
  `).split(`
4
- `),w=T.slice(Math.max(0,T.length-20)),l=w.join(`
4
+ `),w=b.slice(Math.max(0,b.length-20)),l=w.join(`
5
5
  `);if(/\b(plan|proposal)\b/i.test(l)&&/(ready for your review|review (the )?plan|requesting plan approval|awaiting approval|waiting for (your )?approval|approve (the )?plan|approval to proceed)/i.test(l))return`The provider is requesting plan approval.
6
6
  Reply with:
7
7
  - approve
8
8
  - revise: <what to change>
9
- - cancel`;let f=b=>/^(question|clarification|clarify|i need|need more|before i proceed|to proceed|please (confirm|clarify)|which|what|where|when|how|do you)/i.test(b.trim()),q=-1;for(let b=w.length-1;b>=0;b--){let O=w[b].trim();if(O&&(f(O)||O.includes("?"))){q=b;break}}if(q===-1)return;let E=[];for(let b=q;b<w.length&&E.length<8;b++){let O=w[b],N=O.trim();if(E.length>0&&!N||E.length>0&&!/^(options?:|[-*]\s|\d+[\).]\s)/i.test(N)&&!N.includes("?"))break;E.push(O.trimEnd())}let F=E.join(`
10
- `).trim();if(!(F.length<5))return F.length>800?F.slice(0,800).trimEnd():F};try{for(;;){let{done:m,value:R}=await c.read();if(m)break;a+=d.decode(R,{stream:!0});let T=a.split(`
11
- `);a=T.pop()||"";for(let w of T){if(!w.startsWith("data: "))continue;let l=w.slice(6).trim();if(l!=="[DONE]")try{let o=JSON.parse(l);if(o.type==="content_block_start"&&o.content_block?.type==="tool_use"){if(n){yield{type:"tool_use_end",name:n.name};try{let f=JSON.parse(n.json||"{}");n.name==="create_files"&&f&&(Array.isArray(f.files)&&_.push(...f.files),typeof f.summary=="string"&&f.summary.trim()&&(v+=`
9
+ - cancel`;let f=T=>/^(question|clarification|clarify|i need|need more|before i proceed|to proceed|please (confirm|clarify)|which|what|where|when|how|do you)/i.test(T.trim()),F=-1;for(let T=w.length-1;T>=0;T--){let O=w[T].trim();if(O&&(f(O)||O.includes("?"))){F=T;break}}if(F===-1)return;let E=[];for(let T=F;T<w.length&&E.length<8;T++){let O=w[T],N=O.trim();if(E.length>0&&!N||E.length>0&&!/^(options?:|[-*]\s|\d+[\).]\s)/i.test(N)&&!N.includes("?"))break;E.push(O.trimEnd())}let I=E.join(`
10
+ `).trim();if(!(I.length<5))return I.length>800?I.slice(0,800).trimEnd():I};try{for(;;){let{done:m,value:R}=await c.read();if(m)break;a+=d.decode(R,{stream:!0});let b=a.split(`
11
+ `);a=b.pop()||"";for(let w of b){if(!w.startsWith("data: "))continue;let l=w.slice(6).trim();if(l!=="[DONE]")try{let s=JSON.parse(l);if(s.type==="content_block_start"&&s.content_block?.type==="tool_use"){if(n){yield{type:"tool_use_end",name:n.name};try{let f=JSON.parse(n.json||"{}");n.name==="create_files"&&f&&(Array.isArray(f.files)&&_.push(...f.files),typeof f.summary=="string"&&f.summary.trim()&&(v+=`
12
12
  ${f.summary}`)),n.name==="ask_user"&&f&&typeof f.question=="string"&&f.question.trim()&&(x=f.question,Array.isArray(f.options)&&f.options.length&&(x+=`
13
- Options: ${f.options.join(", ")}`))}catch{}finally{n=null}}n={name:o.content_block.name,id:o.content_block.id,json:""},yield{type:"tool_use_start",name:o.content_block.name,id:o.content_block.id}}if(o.type==="content_block_delta"&&(o.delta?.type==="text_delta"&&(v+=o.delta.text,yield{type:"text_delta",text:o.delta.text}),o.delta?.type==="input_json_delta"&&(n&&(n.json+=o.delta.partial_json||""),yield{type:"tool_use_delta",json:o.delta.partial_json})),o.type==="content_block_stop"&&n){yield{type:"tool_use_end",name:n.name};try{let f=JSON.parse(n.json||"{}");n.name==="create_files"&&f&&(Array.isArray(f.files)&&_.push(...f.files),typeof f.summary=="string"&&f.summary.trim()&&(v+=`
13
+ Options: ${f.options.join(", ")}`))}catch{}finally{n=null}}n={name:s.content_block.name,id:s.content_block.id,json:""},yield{type:"tool_use_start",name:s.content_block.name,id:s.content_block.id}}if(s.type==="content_block_delta"&&(s.delta?.type==="text_delta"&&(v+=s.delta.text,yield{type:"text_delta",text:s.delta.text}),s.delta?.type==="input_json_delta"&&(n&&(n.json+=s.delta.partial_json||""),yield{type:"tool_use_delta",json:s.delta.partial_json})),s.type==="content_block_stop"&&n){yield{type:"tool_use_end",name:n.name};try{let f=JSON.parse(n.json||"{}");n.name==="create_files"&&f&&(Array.isArray(f.files)&&_.push(...f.files),typeof f.summary=="string"&&f.summary.trim()&&(v+=`
14
14
  ${f.summary}`)),n.name==="ask_user"&&f&&typeof f.question=="string"&&f.question.trim()&&(x=f.question,Array.isArray(f.options)&&f.options.length&&(x+=`
15
- Options: ${f.options.join(", ")}`))}catch{}finally{n=null}}o.type==="message_delta"&&o.usage&&(k=(o.usage.input_tokens||0)+(o.usage.output_tokens||0)),o.type}catch{}}}}finally{c.releaseLock()}if(n){yield{type:"tool_use_end",name:n.name};try{let m=JSON.parse(n.json||"{}");n.name==="create_files"&&m&&(Array.isArray(m.files)&&_.push(...m.files),typeof m.summary=="string"&&m.summary.trim()&&(v+=`
15
+ Options: ${f.options.join(", ")}`))}catch{}finally{n=null}}s.type==="message_delta"&&s.usage&&(k=(s.usage.input_tokens||0)+(s.usage.output_tokens||0)),s.type}catch{}}}}finally{c.releaseLock()}if(n){yield{type:"tool_use_end",name:n.name};try{let m=JSON.parse(n.json||"{}");n.name==="create_files"&&m&&(Array.isArray(m.files)&&_.push(...m.files),typeof m.summary=="string"&&m.summary.trim()&&(v+=`
16
16
  ${m.summary}`)),n.name==="ask_user"&&m&&typeof m.question=="string"&&m.question.trim()&&(x=m.question,Array.isArray(m.options)&&m.options.length&&(x+=`
17
- Options: ${m.options.join(", ")}`))}catch{}n=null}!x&&_.length===0&&(x=y(v)),yield{type:"done",result:{content:v,files:_,followUp:x,tokensUsed:k}}}buildHeaders(){let t={"Content-Type":"application/json","anthropic-version":"2023-06-01"};return this.authType==="oauth"?(t.Authorization=`Bearer ${this.apiKey}`,t["anthropic-beta"]="claude-code-20250219,oauth-2025-04-20",t["user-agent"]="claude-cli/2.1.2 (external, cli)",t["x-app"]="cli",t["anthropic-dangerous-direct-browser-access"]="true"):t["x-api-key"]=this.apiKey,t}async callApi(t){let e=this.buildHeaders(),i=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:e,body:JSON.stringify(t)});if(!i.ok){let s=await i.text();throw new Error(`Anthropic API error (${i.status}): ${s}`)}return await i.json()}parseResponse(t){let e=[],i="",s;for(let r of t.content)if(r.type==="text"&&(i+=r.text||""),r.type==="tool_use"){if(r.name==="create_files"&&r.input){let u=r.input;e.push(...u.files||[]),u.summary&&(i+=`
18
- ${u.summary}`)}if(r.name==="ask_user"&&r.input){let u=r.input;s=u.question,u.options?.length&&(s+=`
19
- Options: ${u.options.join(", ")}`)}}return{content:i,files:e,followUp:s,tokensUsed:t.usage.input_tokens+t.usage.output_tokens}}};import{execa as D}from"execa";var S="claude-sonnet-4-20250514",$=8192,J={"claude-sonnet-4-20250514":"sonnet","claude-opus-4-20250514":"opus","claude-haiku-4-20250514":"haiku"},G=class{name="claude-code";credential;constructor(){let t=P();if(t){this.credential={type:t.authType,token:t.token};return}let e=I();if(!e)throw new Error(`No Claude credentials found.
17
+ Options: ${m.options.join(", ")}`))}catch{}n=null}!x&&_.length===0&&(x=y(v)),yield{type:"done",result:{content:v,files:_,followUp:x,tokensUsed:k}}}buildHeaders(){let t={"Content-Type":"application/json","anthropic-version":"2023-06-01"};return this.authType==="oauth"?(t.Authorization=`Bearer ${this.apiKey}`,t["anthropic-beta"]="claude-code-20250219,oauth-2025-04-20",t["user-agent"]="claude-cli/2.1.2 (external, cli)",t["x-app"]="cli",t["anthropic-dangerous-direct-browser-access"]="true"):t["x-api-key"]=this.apiKey,t}async callApi(t){let e=this.buildHeaders(),i=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:e,body:JSON.stringify(t)});if(!i.ok){let o=await i.text();throw new Error(`Anthropic API error (${i.status}): ${o}`)}return await i.json()}parseResponse(t){let e=[],i="",o;for(let r of t.content)if(r.type==="text"&&(i+=r.text||""),r.type==="tool_use"){if(r.name==="create_files"&&r.input){let u=r.input;e.push(...u.files||[]),u.summary&&(i+=`
18
+ ${u.summary}`)}if(r.name==="ask_user"&&r.input){let u=r.input;o=u.question,u.options?.length&&(o+=`
19
+ Options: ${u.options.join(", ")}`)}}return{content:i,files:e,followUp:o,tokensUsed:t.usage.input_tokens+t.usage.output_tokens}}};import{execa as D}from"execa";var S="claude-sonnet-4-20250514",$=8192,J={"claude-sonnet-4-20250514":"sonnet","claude-opus-4-20250514":"opus","claude-haiku-4-20250514":"haiku"},G=class{name="claude-code";credential;constructor(){let t=j();if(t){this.credential={type:t.authType,token:t.token};return}let e=M();if(!e)throw new Error(`No Claude credentials found.
20
20
  Options:
21
21
  1. Run \`agentx model\` to configure credentials
22
22
  2. Set ANTHROPIC_API_KEY environment variable
23
- 3. Set ANTHROPIC_OAUTH_TOKEN environment variable`);this.credential={type:e.authType,token:e.token}}async generate(t,e){return this.credential.type==="oauth"?this.generateViaCli(t,e):this.generateViaApi(t,e)}async generateRaw(t,e,i,s){if(this.credential.type==="oauth")throw new Error("generateRaw() not available for OAuth/CLI mode");let r=s?.model||S,u=s?.maxTokens||$,g={model:r,max_tokens:u,system:e,messages:t,tools:i};s?.temperature!==void 0&&(g.temperature=s.temperature);let h={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},p=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:h,body:JSON.stringify(g)});if(!p.ok){let a=await p.text();throw new Error(`Anthropic API error (${p.status}): ${a}`)}let c=await p.json();return{content:c.content.map(a=>a.type==="text"?{type:"text",text:a.text||""}:a.type==="tool_use"?{type:"tool_use",id:a.id||"",name:a.name||"",input:a.input||{}}:{type:"text",text:""}),stop_reason:c.stop_reason,usage:c.usage}}get supportsAgenticLoop(){return this.credential.type==="api-key"}async generateViaCli(t,e){let i=e?.model||P()?.model||S,s=J[i]||i,r=t.find(a=>a.role==="system"),g=t.filter(a=>a.role==="user").map(a=>a.content).join(`
23
+ 3. Set ANTHROPIC_OAUTH_TOKEN environment variable`);this.credential={type:e.authType,token:e.token}}async generate(t,e){return this.credential.type==="oauth"?this.generateViaCli(t,e):this.generateViaApi(t,e)}async generateRaw(t,e,i,o){if(this.credential.type==="oauth")throw new Error("generateRaw() not available for OAuth/CLI mode");let r=o?.model||S,u=o?.maxTokens||$,g={model:r,max_tokens:u,system:e,messages:t,tools:i};o?.temperature!==void 0&&(g.temperature=o.temperature);let h={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},p=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:h,body:JSON.stringify(g)});if(!p.ok){let a=await p.text();throw new Error(`Anthropic API error (${p.status}): ${a}`)}let c=await p.json();return{content:c.content.map(a=>a.type==="text"?{type:"text",text:a.text||""}:a.type==="tool_use"?{type:"tool_use",id:a.id||"",name:a.name||"",input:a.input||{}}:{type:"text",text:""}),stop_reason:c.stop_reason,usage:c.usage}}get supportsAgenticLoop(){return this.credential.type==="api-key"}async generateViaCli(t,e){let i=e?.model||j()?.model||S,o=J[i]||i,r=t.find(a=>a.role==="system"),g=t.filter(a=>a.role==="user").map(a=>a.content).join(`
24
24
 
25
- `),h=["-p","--output-format","json","--model",s,"--dangerously-skip-permissions"];r&&h.push("--append-system-prompt",r.content),h.push(g);let p={...process.env};delete p.ANTHROPIC_API_KEY,delete p.ANTHROPIC_API_KEY_OLD;let c=await D("claude",h,{env:p,extendEnv:!1,reject:!1,timeout:3e5,stdin:"ignore"});if(c.exitCode!==0){let a=c.stderr||c.stdout||"Claude CLI failed";throw new Error(`Claude CLI error: ${a}`)}let d=c.stdout.trim();try{let a=JSON.parse(d);if(a.is_error&&a.result)throw new Error(a.result)}catch(a){if(a.message&&!a.message.includes("JSON"))throw a}return this.parseCliOutput(d)}async generateViaApi(t,e){let i=e?.model||S,s=e?.maxTokens||$,r=t.find(d=>d.role==="system"),u=t.filter(d=>d.role!=="system").map(d=>({role:d.role,content:d.content})),g={model:i,max_tokens:s,messages:u,tools:j()};r&&(g.system=r.content),e?.temperature!==void 0&&(g.temperature=e.temperature);let h={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},p=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:h,body:JSON.stringify(g)});if(!p.ok){let d=await p.text();throw new Error(`Anthropic API error (${p.status}): ${d}`)}let c=await p.json();return this.parseApiResponse(c)}async*stream(t,e){this.credential.type==="oauth"?yield*this.streamViaCli(t,e):yield*this.streamViaApi(t,e)}async*streamViaCli(t,e){let i=e?.model||P()?.model||S,s=J[i]||i,r=t.find(n=>n.role==="system"),g=t.filter(n=>n.role==="user").map(n=>n.content).join(`
25
+ `),h=["-p","--output-format","json","--model",o,"--dangerously-skip-permissions"];r&&h.push("--append-system-prompt",r.content),h.push(g);let p={...process.env};delete p.ANTHROPIC_API_KEY,delete p.ANTHROPIC_API_KEY_OLD;let c=await D("claude",h,{env:p,extendEnv:!1,reject:!1,timeout:3e5,stdin:"ignore"});if(c.exitCode!==0){let a=c.stderr||c.stdout||"Claude CLI failed";throw new Error(`Claude CLI error: ${a}`)}let d=c.stdout.trim();try{let a=JSON.parse(d);if(a.is_error&&a.result)throw new Error(a.result)}catch(a){if(a.message&&!a.message.includes("JSON"))throw a}return this.parseCliOutput(d)}async generateViaApi(t,e){let i=e?.model||S,o=e?.maxTokens||$,r=t.find(d=>d.role==="system"),u=t.filter(d=>d.role!=="system").map(d=>({role:d.role,content:d.content})),g={model:i,max_tokens:o,messages:u,tools:P()};r&&(g.system=r.content),e?.temperature!==void 0&&(g.temperature=e.temperature);let h={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},p=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:h,body:JSON.stringify(g)});if(!p.ok){let d=await p.text();throw new Error(`Anthropic API error (${p.status}): ${d}`)}let c=await p.json();return this.parseApiResponse(c)}async*stream(t,e){this.credential.type==="oauth"?yield*this.streamViaCli(t,e):yield*this.streamViaApi(t,e)}async*streamViaCli(t,e){let i=e?.model||j()?.model||S,o=J[i]||i,r=t.find(n=>n.role==="system"),g=t.filter(n=>n.role==="user").map(n=>n.content).join(`
26
26
 
27
- `),h=["-p","--output-format","stream-json","--model",s,"--dangerously-skip-permissions"];r&&h.push("--append-system-prompt",r.content),h.push(g);let p={...process.env};delete p.ANTHROPIC_API_KEY,delete p.ANTHROPIC_API_KEY_OLD;let c=D("claude",h,{env:p,extendEnv:!1,reject:!1,timeout:3e5,stdin:"ignore"}),d="",a="",_;if(c.stderr&&c.stderr.on("data",n=>{a+=Buffer.isBuffer(n)?n.toString("utf8"):String(n)}),c.stdout){let n=new TextDecoder,y=c.stdout;for await(let m of y){let T=(typeof m=="string"?m:n.decode(m,{stream:!0})).split(`
28
- `).filter(Boolean);for(let w of T)try{let l=JSON.parse(w);if(l.type==="error"){_=String(l.error||l.message||"Claude CLI error");continue}if(l.is_error&&(l.result||l.message)){_=String(l.result||l.message);continue}l.type==="assistant"&&l.message?(d+=l.message,yield{type:"text_delta",text:l.message}):l.type==="result"&&(d=l.result||d)}catch{d+=w,yield{type:"text_delta",text:w}}}}let v=await c;if(v.exitCode!==0&&!_&&(_=(a||v.stderr||v.stdout||"Claude CLI failed").toString().trim()),_){yield{type:"error",error:`Claude CLI error: ${_}`};return}let x=this.extractFilesFromText(d),k=x.length===0?this.inferFollowUpFromText(d):void 0;yield{type:"done",result:{content:d,files:x,followUp:k,tokensUsed:0}}}async*streamViaApi(t,e){let i=e?.model||S,s=e?.maxTokens||$,r=t.find(y=>y.role==="system"),u=t.filter(y=>y.role!=="system").map(y=>({role:y.role,content:y.content})),g={model:i,max_tokens:s,messages:u,tools:j(),stream:!0};r&&(g.system=r.content);let h={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},p=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:h,body:JSON.stringify(g)});if(!p.ok){let y=await p.text();yield{type:"error",error:`Anthropic API error (${p.status}): ${y}`};return}let c=p.body?.getReader();if(!c){yield{type:"error",error:"No response body"};return}let d=new TextDecoder,a="",_="",v=0,x=[],k,n=null;try{for(;;){let{done:y,value:m}=await c.read();if(y)break;a+=d.decode(m,{stream:!0});let R=a.split(`
29
- `);a=R.pop()||"";for(let T of R){if(!T.startsWith("data: "))continue;let w=T.slice(6).trim();if(w!=="[DONE]")try{let l=JSON.parse(w);if(l.type==="content_block_start"&&l.content_block?.type==="tool_use"){if(n){yield{type:"tool_use_end",name:n.name};try{let o=JSON.parse(n.json||"{}");n.name==="create_files"&&o&&(Array.isArray(o.files)&&x.push(...o.files),typeof o.summary=="string"&&o.summary.trim()&&(_+=`
30
- ${o.summary}`)),n.name==="ask_user"&&o&&typeof o.question=="string"&&o.question.trim()&&(k=o.question,Array.isArray(o.options)&&o.options.length&&(k+=`
31
- Options: ${o.options.join(", ")}`))}catch{}finally{n=null}}n={name:l.content_block.name,id:l.content_block.id,json:""},yield{type:"tool_use_start",name:n.name,id:n.id}}if(l.type==="content_block_delta"&&l.delta?.type==="text_delta"&&(_+=l.delta.text,yield{type:"text_delta",text:l.delta.text}),l.type==="content_block_delta"&&l.delta?.type==="input_json_delta"&&(n&&(n.json+=l.delta.partial_json||""),yield{type:"tool_use_delta",json:l.delta.partial_json}),l.type==="content_block_stop"&&n){yield{type:"tool_use_end",name:n.name};try{let o=JSON.parse(n.json||"{}");n.name==="create_files"&&o&&(Array.isArray(o.files)&&x.push(...o.files),typeof o.summary=="string"&&o.summary.trim()&&(_+=`
32
- ${o.summary}`)),n.name==="ask_user"&&o&&typeof o.question=="string"&&o.question.trim()&&(k=o.question,Array.isArray(o.options)&&o.options.length&&(k+=`
33
- Options: ${o.options.join(", ")}`))}catch{}finally{n=null}}l.type==="message_delta"&&l.usage&&(v=(l.usage.input_tokens||0)+(l.usage.output_tokens||0))}catch{}}}}finally{c.releaseLock()}if(n){yield{type:"tool_use_end",name:n.name};try{let y=JSON.parse(n.json||"{}");n.name==="create_files"&&y&&(Array.isArray(y.files)&&x.push(...y.files),typeof y.summary=="string"&&y.summary.trim()&&(_+=`
27
+ `),h=["-p","--output-format","stream-json","--model",o,"--dangerously-skip-permissions"];r&&h.push("--append-system-prompt",r.content),h.push(g);let p={...process.env};delete p.ANTHROPIC_API_KEY,delete p.ANTHROPIC_API_KEY_OLD;let c=D("claude",h,{env:p,extendEnv:!1,reject:!1,timeout:3e5,stdin:"ignore"}),d="",a="",_;if(c.stderr&&c.stderr.on("data",n=>{a+=Buffer.isBuffer(n)?n.toString("utf8"):String(n)}),c.stdout){let n=new TextDecoder,y=c.stdout;for await(let m of y){let b=(typeof m=="string"?m:n.decode(m,{stream:!0})).split(`
28
+ `).filter(Boolean);for(let w of b)try{let l=JSON.parse(w);if(l.type==="error"){_=String(l.error||l.message||"Claude CLI error");continue}if(l.is_error&&(l.result||l.message)){_=String(l.result||l.message);continue}l.type==="assistant"&&l.message?(d+=l.message,yield{type:"text_delta",text:l.message}):l.type==="result"&&(d=l.result||d)}catch{d+=w,yield{type:"text_delta",text:w}}}}let v=await c;if(v.exitCode!==0&&!_&&(_=(a||v.stderr||v.stdout||"Claude CLI failed").toString().trim()),_){yield{type:"error",error:`Claude CLI error: ${_}`};return}let x=this.extractFilesFromText(d),k=x.length===0?this.inferFollowUpFromText(d):void 0;yield{type:"done",result:{content:d,files:x,followUp:k,tokensUsed:0}}}async*streamViaApi(t,e){let i=e?.model||S,o=e?.maxTokens||$,r=t.find(y=>y.role==="system"),u=t.filter(y=>y.role!=="system").map(y=>({role:y.role,content:y.content})),g={model:i,max_tokens:o,messages:u,tools:P(),stream:!0};r&&(g.system=r.content);let h={"Content-Type":"application/json","anthropic-version":"2023-06-01","x-api-key":this.credential.token},p=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:h,body:JSON.stringify(g)});if(!p.ok){let y=await p.text();yield{type:"error",error:`Anthropic API error (${p.status}): ${y}`};return}let c=p.body?.getReader();if(!c){yield{type:"error",error:"No response body"};return}let d=new TextDecoder,a="",_="",v=0,x=[],k,n=null;try{for(;;){let{done:y,value:m}=await c.read();if(y)break;a+=d.decode(m,{stream:!0});let R=a.split(`
29
+ `);a=R.pop()||"";for(let b of R){if(!b.startsWith("data: "))continue;let w=b.slice(6).trim();if(w!=="[DONE]")try{let l=JSON.parse(w);if(l.type==="content_block_start"&&l.content_block?.type==="tool_use"){if(n){yield{type:"tool_use_end",name:n.name};try{let s=JSON.parse(n.json||"{}");n.name==="create_files"&&s&&(Array.isArray(s.files)&&x.push(...s.files),typeof s.summary=="string"&&s.summary.trim()&&(_+=`
30
+ ${s.summary}`)),n.name==="ask_user"&&s&&typeof s.question=="string"&&s.question.trim()&&(k=s.question,Array.isArray(s.options)&&s.options.length&&(k+=`
31
+ Options: ${s.options.join(", ")}`))}catch{}finally{n=null}}n={name:l.content_block.name,id:l.content_block.id,json:""},yield{type:"tool_use_start",name:n.name,id:n.id}}if(l.type==="content_block_delta"&&l.delta?.type==="text_delta"&&(_+=l.delta.text,yield{type:"text_delta",text:l.delta.text}),l.type==="content_block_delta"&&l.delta?.type==="input_json_delta"&&(n&&(n.json+=l.delta.partial_json||""),yield{type:"tool_use_delta",json:l.delta.partial_json}),l.type==="content_block_stop"&&n){yield{type:"tool_use_end",name:n.name};try{let s=JSON.parse(n.json||"{}");n.name==="create_files"&&s&&(Array.isArray(s.files)&&x.push(...s.files),typeof s.summary=="string"&&s.summary.trim()&&(_+=`
32
+ ${s.summary}`)),n.name==="ask_user"&&s&&typeof s.question=="string"&&s.question.trim()&&(k=s.question,Array.isArray(s.options)&&s.options.length&&(k+=`
33
+ Options: ${s.options.join(", ")}`))}catch{}finally{n=null}}l.type==="message_delta"&&l.usage&&(v=(l.usage.input_tokens||0)+(l.usage.output_tokens||0))}catch{}}}}finally{c.releaseLock()}if(n){yield{type:"tool_use_end",name:n.name};try{let y=JSON.parse(n.json||"{}");n.name==="create_files"&&y&&(Array.isArray(y.files)&&x.push(...y.files),typeof y.summary=="string"&&y.summary.trim()&&(_+=`
34
34
  ${y.summary}`)),n.name==="ask_user"&&y&&typeof y.question=="string"&&y.question.trim()&&(k=y.question,Array.isArray(y.options)&&y.options.length&&(k+=`
35
- Options: ${y.options.join(", ")}`))}catch{}n=null}x.length===0&&x.push(...this.extractFilesFromText(_)),!k&&x.length===0&&(k=this.inferFollowUpFromText(_)),yield{type:"done",result:{content:_,files:x,followUp:k,tokensUsed:v}}}parseCliOutput(t){let e;try{e=JSON.parse(t)}catch{let u=this.inferFollowUpFromText(t.trim());return{content:t.trim(),files:[],followUp:u,tokensUsed:0}}let i=e.result||e.text||e.content||"",s=this.extractFilesFromText(i),r=s.length===0?this.inferFollowUpFromText(i):void 0;return{content:i,files:s,followUp:r,tokensUsed:e.usage?(e.usage.input_tokens||0)+(e.usage.output_tokens||0):0}}extractFilesFromText(t){let e=[],i=/```[\w]*\s*([\w/._-]+\.\w+)\n([\s\S]*?)```/g,s;for(;(s=i.exec(t))!==null;){let r=s[1],u=s[2];r&&u&&e.push({path:r,content:u.trimEnd()})}return e}inferFollowUpFromText(t){let e=(t||"").trim();if(!e||e.includes("```"))return;let i=e.replace(/\r\n/g,`
35
+ Options: ${y.options.join(", ")}`))}catch{}n=null}x.length===0&&x.push(...this.extractFilesFromText(_)),!k&&x.length===0&&(k=this.inferFollowUpFromText(_)),yield{type:"done",result:{content:_,files:x,followUp:k,tokensUsed:v}}}parseCliOutput(t){let e;try{e=JSON.parse(t)}catch{let u=this.inferFollowUpFromText(t.trim());return{content:t.trim(),files:[],followUp:u,tokensUsed:0}}let i=e.result||e.text||e.content||"",o=this.extractFilesFromText(i),r=o.length===0?this.inferFollowUpFromText(i):void 0;return{content:i,files:o,followUp:r,tokensUsed:e.usage?(e.usage.input_tokens||0)+(e.usage.output_tokens||0):0}}extractFilesFromText(t){let e=[],i=/```[\w]*\s*([\w/._-]+\.\w+)\n([\s\S]*?)```/g,o;for(;(o=i.exec(t))!==null;){let r=o[1],u=o[2];r&&u&&e.push({path:r,content:u.trimEnd()})}return e}inferFollowUpFromText(t){let e=(t||"").trim();if(!e||e.includes("```"))return;let i=e.replace(/\r\n/g,`
36
36
  `).split(`
37
- `),s=i.slice(Math.max(0,i.length-20)),r=s.join(`
37
+ `),o=i.slice(Math.max(0,i.length-20)),r=o.join(`
38
38
  `);if(/\b(plan|proposal)\b/i.test(r)&&/(ready for your review|review (the )?plan|requesting plan approval|awaiting approval|waiting for (your )?approval|approve (the )?plan|approval to proceed)/i.test(r))return`The provider is requesting plan approval.
39
39
  Reply with:
40
40
  - approve
41
41
  - revise: <what to change>
42
- - cancel`;let g=d=>/^(question|clarification|clarify|i need|need more|before i proceed|to proceed|please (confirm|clarify)|which|what|where|when|how|do you)/i.test(d.trim()),h=-1;for(let d=s.length-1;d>=0;d--){let a=s[d].trim();if(a&&(g(a)||a.includes("?"))){h=d;break}}if(h===-1)return;let p=[];for(let d=h;d<s.length&&p.length<8;d++){let a=s[d],_=a.trim();if(p.length>0&&!_||p.length>0&&!/^(options?:|[-*]\s|\d+[\).]\s)/i.test(_)&&!_.includes("?"))break;p.push(a.trimEnd())}let c=p.join(`
43
- `).trim();if(!(c.length<5))return c.length>800?c.slice(0,800).trimEnd():c}parseApiResponse(t){let e=[],i="",s;for(let r of t.content)if(r.type==="text"&&(i+=r.text||""),r.type==="tool_use"){if(r.name==="create_files"&&r.input){let u=r.input;e.push(...u.files||[]),u.summary&&(i+=`
44
- ${u.summary}`)}if(r.name==="ask_user"&&r.input){let u=r.input;s=u.question,u.options?.length&&(s+=`
45
- Options: ${u.options.join(", ")}`)}}return{content:i,files:e,followUp:s,tokensUsed:t.usage.input_tokens+t.usage.output_tokens}}};function oe(A="claude-code",t){let e=A;if(A==="claude-code"&&!t){let i=P();i&&(e=i.provider)}switch(e){case"claude-code":return new G;case"claude":return new C(t);case"openai":throw new Error("OpenAI provider coming soon. Set provider to 'claude-code' or contribute at github.com/anis-marrouchi/agentx");case"ollama":throw new Error("Ollama provider coming soon. Set provider to 'claude-code' or contribute at github.com/anis-marrouchi/agentx");default:throw new Error(`Unknown provider: ${e}. Supported: claude-code, claude`)}}export{K as a,j as b,B as c,H as d,C as e,G as f,oe as g};
46
- //# sourceMappingURL=chunk-MGMZNJCE.js.map
42
+ - cancel`;let g=d=>/^(question|clarification|clarify|i need|need more|before i proceed|to proceed|please (confirm|clarify)|which|what|where|when|how|do you)/i.test(d.trim()),h=-1;for(let d=o.length-1;d>=0;d--){let a=o[d].trim();if(a&&(g(a)||a.includes("?"))){h=d;break}}if(h===-1)return;let p=[];for(let d=h;d<o.length&&p.length<8;d++){let a=o[d],_=a.trim();if(p.length>0&&!_||p.length>0&&!/^(options?:|[-*]\s|\d+[\).]\s)/i.test(_)&&!_.includes("?"))break;p.push(a.trimEnd())}let c=p.join(`
43
+ `).trim();if(!(c.length<5))return c.length>800?c.slice(0,800).trimEnd():c}parseApiResponse(t){let e=[],i="",o;for(let r of t.content)if(r.type==="text"&&(i+=r.text||""),r.type==="tool_use"){if(r.name==="create_files"&&r.input){let u=r.input;e.push(...u.files||[]),u.summary&&(i+=`
44
+ ${u.summary}`)}if(r.name==="ask_user"&&r.input){let u=r.input;o=u.question,u.options?.length&&(o+=`
45
+ Options: ${u.options.join(", ")}`)}}return{content:i,files:e,followUp:o,tokensUsed:t.usage.input_tokens+t.usage.output_tokens}}};function se(A="claude-code",t){let e=A;if(A==="claude-code"&&!t){let i=j();i&&(e=i.provider)}switch(e){case"claude-code":return new G;case"claude":return new C(t);case"openai":throw new Error("OpenAI provider coming soon. Set provider to 'claude-code' or contribute at github.com/anis-marrouchi/agentx");case"ollama":throw new Error("Ollama provider coming soon. Set provider to 'claude-code' or contribute at github.com/anis-marrouchi/agentx");default:throw new Error(`Unknown provider: ${e}. Supported: claude-code, claude`)}}export{K as a,P as b,B as c,H as d,C as e,G as f,se as g};
46
+ //# sourceMappingURL=chunk-KXZMYLHQ.js.map