agentix-cli 0.8.0 → 0.13.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 (71) hide show
  1. package/README.md +387 -116
  2. package/dist/agent-5KIMJI3F.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-CJ45Y2IR.js +12 -0
  7. package/dist/chunk-CJ45Y2IR.js.map +1 -0
  8. package/dist/chunk-D6EDMQRV.js +108 -0
  9. package/dist/chunk-D6EDMQRV.js.map +1 -0
  10. package/dist/chunk-DSYKYZMT.js +2 -0
  11. package/dist/chunk-DSYKYZMT.js.map +1 -0
  12. package/dist/chunk-HI24KAEY.js +54 -0
  13. package/dist/chunk-HI24KAEY.js.map +1 -0
  14. package/dist/{chunk-MGMZNJCE.js → chunk-KXZMYLHQ.js} +27 -27
  15. package/dist/chunk-KXZMYLHQ.js.map +1 -0
  16. package/dist/chunk-MCJUAE6V.js +6 -0
  17. package/dist/chunk-MCJUAE6V.js.map +1 -0
  18. package/dist/chunk-QOYAX2FT.js +2 -0
  19. package/dist/chunk-QOYAX2FT.js.map +1 -0
  20. package/dist/chunk-QZP65I2H.js +45 -0
  21. package/dist/chunk-QZP65I2H.js.map +1 -0
  22. package/dist/chunk-T25UEXVK.js +126 -0
  23. package/dist/chunk-T25UEXVK.js.map +1 -0
  24. package/dist/chunk-VH23CDHL.js +157 -0
  25. package/dist/chunk-VH23CDHL.js.map +1 -0
  26. package/dist/chunk-WJ6ZF6EZ.js +6 -0
  27. package/dist/chunk-WJ6ZF6EZ.js.map +1 -0
  28. package/dist/chunk-ZRYBSI5G.js +23 -0
  29. package/dist/chunk-ZRYBSI5G.js.map +1 -0
  30. package/dist/cli.js +277 -36
  31. package/dist/cli.js.map +1 -1
  32. package/dist/compaction-7I3E5QUO.js +28 -0
  33. package/dist/compaction-7I3E5QUO.js.map +1 -0
  34. package/dist/config-HAD5E4YX.js +2 -0
  35. package/dist/debug-N3B5NVJU.js +2 -0
  36. package/dist/heal-OTGT5HHJ.js +2 -0
  37. package/dist/index.d.ts +1849 -368
  38. package/dist/index.js +39 -35
  39. package/dist/index.js.map +1 -1
  40. package/dist/loader-YQE6XJBT.js +2 -0
  41. package/dist/loader-YQE6XJBT.js.map +1 -0
  42. package/dist/memory-extract-RGPUPMKU.js +2 -0
  43. package/dist/memory-extract-RGPUPMKU.js.map +1 -0
  44. package/dist/{providers-AVYG63KK.js → providers-G3WZ4RVJ.js} +2 -2
  45. package/dist/providers-G3WZ4RVJ.js.map +1 -0
  46. package/dist/registry-CDWY7CLL.js +2 -0
  47. package/dist/registry-CDWY7CLL.js.map +1 -0
  48. package/dist/subagent-WV7QKQ3L.js +3 -0
  49. package/dist/subagent-WV7QKQ3L.js.map +1 -0
  50. package/dist/usage-dashboard-2TJQBFSH.js +404 -0
  51. package/dist/usage-dashboard-2TJQBFSH.js.map +1 -0
  52. package/dist/workspace-setup-QQTCJY4B.js +2 -0
  53. package/dist/workspace-setup-QQTCJY4B.js.map +1 -0
  54. package/package.json +4 -1
  55. package/dist/agent-K2YOEOJ5.js +0 -2
  56. package/dist/chunk-F73GPYCO.js +0 -106
  57. package/dist/chunk-F73GPYCO.js.map +0 -1
  58. package/dist/chunk-FRFR27IN.js +0 -3
  59. package/dist/chunk-FRFR27IN.js.map +0 -1
  60. package/dist/chunk-MGMZNJCE.js.map +0 -1
  61. package/dist/chunk-NGKOM4ZZ.js +0 -137
  62. package/dist/chunk-NGKOM4ZZ.js.map +0 -1
  63. package/dist/chunk-Z4GC5D6D.js +0 -12
  64. package/dist/chunk-Z4GC5D6D.js.map +0 -1
  65. package/dist/heal-UV5A6B5T.js +0 -2
  66. package/dist/loader-6VSM6FSY.js +0 -2
  67. /package/dist/{agent-K2YOEOJ5.js.map → agent-5KIMJI3F.js.map} +0 -0
  68. /package/dist/{chunk-X7UN6JAA.js.map → chunk-6MKAXEE5.js.map} +0 -0
  69. /package/dist/{heal-UV5A6B5T.js.map → config-HAD5E4YX.js.map} +0 -0
  70. /package/dist/{loader-6VSM6FSY.js.map → debug-N3B5NVJU.js.map} +0 -0
  71. /package/dist/{providers-AVYG63KK.js.map → heal-OTGT5HHJ.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/patterns.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 historyContext?: 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 // Build prompt with full context (landscape, memory, patterns, etc.)\n const prompt = buildPrompt(agent, task, historyContext)\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 historyContext?: 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 // Build full prompt with context (landscape, memory, patterns, etc.)\n const fullTask = historyContext\n ? `${historyContext}\\n\\n${task.message}`\n : task.message\n\n const result = await generate({\n task: fullTask,\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, historyContext)\n }\n\n case \"orchestrator\": {\n const providerName = agent.provider || \"claude-code\"\n const apiKey = providers[providerName]?.apiKey\n return executeOrchestrator(agent, task, apiKey, historyContext)\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<{ compacted: boolean; qualityScore?: number; lostEntities?: string[]; drift?: import(\"./drift-detection\").DriftReport }> {\n const session = this.getSession(agentId, channel, chatId)\n const { needsCompaction, compactSession, applyCompaction } = await import(\"./compaction\")\n\n if (!needsCompaction(session.messages)) return { compacted: false }\n\n const result = await compactSession(session.messages, agentId, memoryStore)\n if (result.compactedCount === 0) return { compacted: 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 {\n compacted: true,\n qualityScore: result.qualityScore,\n lostEntities: result.lostEntities,\n drift: result.drift,\n }\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, buildIndexCached, 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\n // Version the previous content before overwriting (immutable history)\n if (existing) {\n this.saveVersion(path, fullPath)\n }\n\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 // --- Article Versioning ---\n\n /**\n * Save current article content as an immutable version before overwriting.\n * Versions stored in _versions/{article-path}/{timestamp}.md\n */\n private saveVersion(articlePath: string, fullPath: string): void {\n try {\n if (!existsSync(fullPath)) return\n const content = readFileSync(fullPath, \"utf-8\")\n const ts = new Date().toISOString().replace(/[:.]/g, \"-\")\n const versionDir = resolve(this.baseDir, \"_versions\", articlePath.replace(/\\.md$/, \"\"))\n mkdirSync(versionDir, { recursive: true })\n writeFileSync(resolve(versionDir, `${ts}.md`), content)\n } catch {\n // Version save is best-effort\n }\n }\n\n /**\n * List all versions of an article (newest first).\n */\n getVersions(articlePath: string): Array<{ timestamp: string; path: string }> {\n const versionDir = resolve(this.baseDir, \"_versions\", articlePath.replace(/\\.md$/, \"\"))\n if (!existsSync(versionDir)) return []\n\n try {\n return readdirSync(versionDir)\n .filter(f => f.endsWith(\".md\"))\n .sort()\n .reverse()\n .map(f => ({\n timestamp: f.replace(/\\.md$/, \"\").replace(/-/g, (m, i) => i < 19 ? (i === 10 ? \"T\" : i === 13 || i === 16 ? \":\" : \"-\") : m),\n path: resolve(versionDir, f),\n }))\n } catch {\n return []\n }\n }\n\n /**\n * Restore a specific version of an article.\n */\n restoreVersion(articlePath: string, versionTimestamp: string): boolean {\n const versions = this.getVersions(articlePath)\n const version = versions.find(v => v.timestamp.startsWith(versionTimestamp))\n if (!version) return false\n\n try {\n const content = readFileSync(version.path, \"utf-8\")\n const fullPath = resolve(this.baseDir, articlePath)\n // Save current as a version too before restoring\n this.saveVersion(articlePath, fullPath)\n writeFileSync(fullPath, content)\n this.appendLog(\"restore\", `${articlePath} restored to ${versionTimestamp}`)\n return true\n } catch {\n return false\n }\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 (cached to disk)\n const docs = articles.map((a) => a.content)\n const cachePath = resolve(this.baseDir, \"_bm25_cache.json\")\n const index = buildIndexCached(docs, cachePath)\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 (cached)\n const docs = articles.map(\n (a) => `${a.meta.title} ${(a.meta.tags || []).join(\" \")} ${a.content}`,\n )\n const cachePath = resolve(this.baseDir, \"_bm25_relevance_cache.json\")\n const index = buildIndexCached(docs, cachePath)\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 // Behavioral patterns (self-improving loop)\n patternContext?: string // from PatternStore.buildContext()\n\n // Auto-injected skills (matched to current message)\n skillInjection?: string // from getAutoInjectSkills()\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.2 Auto-injected skills (matched to current task)\n if (input.skillInjection) {\n layers.push({\n name: \"skills\",\n priority: 6.2,\n maxTokens: budget(\"skills\", 2000),\n content: input.skillInjection,\n tags: [\"skills\", \"auto-inject\"],\n })\n }\n\n // 6.3 Behavioral patterns (self-improving loop)\n if (input.patternContext) {\n layers.push({\n name: \"patterns\",\n priority: 6.3,\n maxTokens: budget(\"patterns\", 400),\n content: input.patternContext,\n tags: [\"patterns\", \"behavioral\", \"self-improving\"],\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 { buildIndexCached, 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 // Spaced repetition fields\n accessCount?: number\n lastAccessed?: string\n nextReview?: string\n /** Review interval in days — doubles on each successful recall */\n intervalDays?: number\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 (cached)\n const docs = memories.map((m) => `${m.keywords.join(\" \")} ${m.content}`)\n const cachePath = resolve(this.memoryDir, `${agentId}_bm25_cache.json`)\n const index = buildIndexCached(docs, cachePath)\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 const selected = matched\n .sort((a, b) => b.score - a.score)\n .slice(0, limit)\n .map((s) => s.memory)\n\n // Track access for spaced repetition (fire-and-forget)\n if (selected.length > 0) {\n try { this.recordAccess(agentId, selected.map(m => m.id)) } catch {}\n }\n\n return selected\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 * Record that memories were accessed (for spaced repetition tracking).\n */\n recordAccess(agentId: string, memoryIds: string[]): void {\n if (memoryIds.length === 0) return\n const memories = this.getAll(agentId)\n const idSet = new Set(memoryIds)\n let changed = false\n\n for (const m of memories) {\n if (idSet.has(m.id)) {\n m.accessCount = (m.accessCount || 0) + 1\n m.lastAccessed = new Date().toISOString()\n // Double the review interval (spaced repetition: 1 → 2 → 4 → 8 → 16 days)\n const currentInterval = m.intervalDays || 1\n m.intervalDays = Math.min(currentInterval * 2, 30)\n m.nextReview = new Date(Date.now() + m.intervalDays * 86400000).toISOString()\n changed = true\n }\n }\n\n if (changed) {\n writeFileSync(\n this.filePath(agentId),\n memories.map(m => JSON.stringify(m)).join(\"\\n\") + \"\\n\",\n )\n }\n }\n\n /**\n * Get memories due for review (spaced repetition).\n * Returns facts whose nextReview date has passed or that have never been reviewed.\n */\n getDueForReview(agentId: string, limit: number = 5): MemoryFact[] {\n const memories = this.getAll(agentId)\n const now = Date.now()\n\n return memories\n .filter(m => {\n // Skip task-state (ephemeral)\n if (m.category === \"task-state\") return false\n // Never reviewed → due\n if (!m.nextReview) return true\n // Past review date → due\n return new Date(m.nextReview).getTime() <= now\n })\n .sort((a, b) => {\n // Prioritize: never reviewed, then oldest nextReview, then most accessed\n if (!a.nextReview && b.nextReview) return -1\n if (a.nextReview && !b.nextReview) return 1\n if (a.nextReview && b.nextReview) {\n return new Date(a.nextReview).getTime() - new Date(b.nextReview).getTime()\n }\n return (a.accessCount || 0) - (b.accessCount || 0)\n })\n .slice(0, limit)\n }\n\n /**\n * Build a recall prompt for memories due for review.\n * Injected into heartbeat context so the agent proactively recalls facts.\n */\n buildRecallContext(agentId: string): string {\n const due = this.getDueForReview(agentId, 5)\n if (due.length === 0) return \"\"\n\n const lines = [\"[Memory Recall — facts due for review, verify they are still accurate]\"]\n for (const m of due) {\n const age = Math.round((Date.now() - new Date(m.createdAt).getTime()) / 86400000)\n lines.push(`- [${m.category}] ${m.content} (${age}d old, accessed ${m.accessCount || 0}x)`)\n }\n lines.push(\"[If any fact is outdated, note the correction. Otherwise, acknowledge recall.]\")\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, writeFileSync, appendFileSync, mkdirSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { buildIndexCached, scoreAll } from \"../memory/bm25\"\n\n// --- Behavioral Pattern Store ---\n//\n// Agents learn HOW to work, not just WHAT they know.\n// After each response, Haiku extracts behavioral patterns:\n// \"When user asks about deployment, check CI status first\"\n// \"Code reviews should mention test coverage\"\n//\n// Before each prompt, relevant patterns are injected so the agent\n// improves over time — a self-correcting loop.\n\nexport interface BehavioralPattern {\n id: string\n agentId: string\n pattern: string // the learned behavior\n context: string // when this applies\n confidence: number // 0-1, increases with validation\n accessCount: number\n createdAt: string\n lastUsed?: string\n source: { channel: string; date: string }\n}\n\nconst MAX_PATTERNS = 50\nconst EXTRACTION_MODEL = \"claude-haiku-4-20250514\"\n\nconst PATTERN_EXTRACTION_PROMPT = `You are a behavioral pattern extractor. Given a conversation between a user and an AI agent, extract behavioral patterns — lessons about HOW to approach tasks, not facts about the world.\n\nExtract patterns like:\n- \"When asked about X, the approach that works is Y\"\n- \"User prefers Z style of communication\"\n- \"For deployment tasks, always check A before doing B\"\n- \"This codebase uses pattern X, so generate code following X\"\n\nSKIP:\n- Factual information (names, dates, URLs)\n- Routine task completions\n- Greetings or small talk\n\nOutput a JSON array:\n[{\"pattern\":\"the behavioral lesson\",\"context\":\"when this applies\",\"confidence\":0.5}]\n\nIf nothing worth extracting, output: []`\n\nexport class PatternStore {\n private patternsDir: string\n\n constructor(baseDir: string = process.cwd()) {\n this.patternsDir = resolve(baseDir, \".agentx/patterns\")\n if (!existsSync(this.patternsDir)) {\n mkdirSync(this.patternsDir, { recursive: true })\n }\n }\n\n private filePath(agentId: string): string {\n return resolve(this.patternsDir, `${agentId}.jsonl`)\n }\n\n getAll(agentId: string): BehavioralPattern[] {\n const file = this.filePath(agentId)\n if (!existsSync(file)) return []\n try {\n return readFileSync(file, \"utf-8\")\n .split(\"\\n\")\n .filter(l => l.trim())\n .map(l => { try { return JSON.parse(l) } catch { return null } })\n .filter((p): p is BehavioralPattern => p !== null)\n } catch {\n return []\n }\n }\n\n addPattern(agentId: string, pattern: Omit<BehavioralPattern, \"id\" | \"createdAt\" | \"accessCount\">): void {\n const entry: BehavioralPattern = {\n ...pattern,\n id: `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`,\n accessCount: 0,\n createdAt: new Date().toISOString(),\n }\n appendFileSync(this.filePath(agentId), JSON.stringify(entry) + \"\\n\")\n }\n\n /**\n * Find patterns relevant to the current task.\n */\n findRelevant(message: string, agentId: string, limit: number = 5): BehavioralPattern[] {\n const patterns = this.getAll(agentId)\n if (patterns.length === 0) return []\n\n const docs = patterns.map(p => `${p.context} ${p.pattern}`)\n const cachePath = resolve(this.patternsDir, `${agentId}_bm25_cache.json`)\n const index = buildIndexCached(docs, cachePath)\n const scored = scoreAll(message, index)\n\n const results = scored\n .slice(0, limit)\n .map(s => patterns[s.docIndex])\n .filter(p => p.confidence >= 0.3) // only confident patterns\n\n // Track access\n if (results.length > 0) {\n this.recordAccess(agentId, results.map(p => p.id))\n }\n\n return results\n }\n\n /**\n * Build context string from relevant patterns for prompt injection.\n */\n buildContext(patterns: BehavioralPattern[]): string {\n if (patterns.length === 0) return \"\"\n\n const lines = [\"[Learned Patterns — behavioral lessons from past interactions]\"]\n for (const p of patterns) {\n lines.push(`- ${p.pattern} (context: ${p.context}, confidence: ${Math.round(p.confidence * 100)}%)`)\n }\n lines.push(\"[Apply these patterns when relevant to the current task]\")\n return lines.join(\"\\n\")\n }\n\n /**\n * Check if a similar pattern already exists.\n */\n hasSimilar(agentId: string, pattern: string): boolean {\n const existing = this.getAll(agentId)\n const words = pattern.toLowerCase().split(/\\s+/).filter(w => w.length > 3)\n return existing.some(p => {\n const pWords = p.pattern.toLowerCase()\n const overlap = words.filter(w => pWords.includes(w)).length\n return overlap >= words.length * 0.6\n })\n }\n\n private recordAccess(agentId: string, ids: string[]): void {\n const patterns = this.getAll(agentId)\n const idSet = new Set(ids)\n let changed = false\n for (const p of patterns) {\n if (idSet.has(p.id)) {\n p.accessCount++\n p.lastUsed = new Date().toISOString()\n // Boost confidence slightly on each use (max 1.0)\n p.confidence = Math.min(1.0, p.confidence + 0.05)\n changed = true\n }\n }\n if (changed) {\n writeFileSync(this.filePath(agentId), patterns.map(p => JSON.stringify(p)).join(\"\\n\") + \"\\n\")\n }\n }\n\n /**\n * Prune low-confidence or old patterns. Cap at MAX_PATTERNS.\n */\n prune(agentId: string): void {\n let patterns = this.getAll(agentId)\n if (patterns.length <= MAX_PATTERNS) return\n\n // Sort by confidence * accessCount (most valuable first)\n patterns.sort((a, b) => (b.confidence * b.accessCount) - (a.confidence * a.accessCount))\n patterns = patterns.slice(0, MAX_PATTERNS)\n writeFileSync(this.filePath(agentId), patterns.map(p => JSON.stringify(p)).join(\"\\n\") + \"\\n\")\n }\n}\n\n/**\n * Extract behavioral patterns from a conversation (fire-and-forget).\n */\nexport async function extractPatterns(\n agentId: string,\n userMessage: string,\n agentResponse: string,\n source: { channel: string; date: string },\n store: PatternStore,\n): Promise<void> {\n if (userMessage.length < 30 && agentResponse.length < 100) return\n\n const { createProvider } = await import(\"@/agent/providers\")\n const provider = createProvider(\"claude\")\n\n const result = await provider.generate(\n [\n { role: \"system\", content: PATTERN_EXTRACTION_PROMPT },\n { role: \"user\", content: `User: ${userMessage.slice(0, 500)}\\n\\nAgent: ${agentResponse.slice(0, 1000)}` },\n ],\n { model: EXTRACTION_MODEL, maxTokens: 512 },\n )\n\n const jsonMatch = result.content.trim().match(/\\[[\\s\\S]*\\]/)\n if (!jsonMatch) return\n\n const patterns = JSON.parse(jsonMatch[0]) as Array<{\n pattern: string\n context: string\n confidence: number\n }>\n\n if (!Array.isArray(patterns) || patterns.length === 0) return\n\n for (const p of patterns) {\n if (store.hasSimilar(agentId, p.pattern)) continue\n store.addPattern(agentId, {\n agentId,\n pattern: p.pattern,\n context: p.context,\n confidence: p.confidence || 0.5,\n source,\n })\n }\n\n // Probabilistic pruning\n if (Math.random() < 0.05) store.prune(agentId)\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, detectSoulSwitch, listSoulProfiles } from \"./bootstrap\"\nimport { PatternStore, extractPatterns } from \"./patterns\"\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 patternStore: PatternStore\n private rateLimiter: RateLimiter\n private tokenTracker: TokenTracker\n private landscape?: LandscapeBuilder\n private messageQueue: MessageQueue\n /** Active soul profile per agent+chat session: \"agentId:channel:chatId\" → profile name */\n private activeSouls: Map<string, string> = new Map()\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.patternStore = new PatternStore()\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 // Load behavioral patterns (self-improving loop)\n const relevantPatterns = this.patternStore.findRelevant(task.message, task.agentId, 5)\n const patternContext = this.patternStore.buildContext(relevantPatterns)\n\n // Auto-inject skills matched to current message\n let skillInjection = \"\"\n try {\n const { loadLocalSkills, getAutoInjectSkills } = await import(\"@/agent/skills/loader\")\n const skills = await loadLocalSkills(state.def.workspace)\n skillInjection = getAutoInjectSkills(skills, task.message)\n } catch {\n // Skill loading is optional\n }\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 compactResult = await this.sessions.compactIfNeeded(\n task.agentId, channel, chatId, this.memoryStore,\n )\n if (compactResult.compacted) {\n const quality = compactResult.qualityScore ?? \"?\"\n const lost = compactResult.lostEntities?.length ?? 0\n this.log(`[${task.agentId}] session compacted for ${channel}:${chatId} (quality: ${quality}%, ${lost} entities lost)`)\n if (compactResult.lostEntities?.length) {\n this.log(`[${task.agentId}] lost entities: ${compactResult.lostEntities.slice(0, 5).join(\", \")}`)\n }\n if (compactResult.drift) {\n const d = compactResult.drift\n this.log(`[${task.agentId}] DRIFT DETECTED: score=${d.overallScore} (lexicon=${d.lexiconDecay}, tools=${d.toolShift}, semantic=${d.semanticDrift})`)\n if (d.lostWords.length) this.log(`[${task.agentId}] lost domain words: ${d.lostWords.slice(0, 5).join(\", \")}`)\n }\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 // Soul switching: detect /soul command and track active profile\n const soulSessionKey = `${task.agentId}:${channel}:${chatId}`\n const soulSwitch = detectSoulSwitch(task.message)\n if (soulSwitch) {\n if (soulSwitch === \"default\") {\n this.activeSouls.delete(soulSessionKey)\n this.log(`[${task.agentId}] Soul reset to default`)\n } else {\n this.activeSouls.set(soulSessionKey, soulSwitch)\n this.log(`[${task.agentId}] Soul switched to: ${soulSwitch}`)\n }\n }\n const activeSoul = this.activeSouls.get(soulSessionKey)\n\n // Load bootstrap identity files (SOUL.md or SOUL.{profile}.md)\n const bootstrapFiles = loadBootstrapFiles(state.def.workspace, activeSoul)\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 patternContext: patternContext || undefined,\n skillInjection: skillInjection || 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 // Patterns: extract behavioral patterns (fire-and-forget)\n extractPatterns(\n task.agentId,\n task.message,\n response.content,\n { channel, date: new Date().toISOString().slice(0, 10) },\n this.patternStore,\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","fullTask","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","memoryStore","needsCompaction","compactSession","applyCompaction","result","totalChars","sum","m","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","articlePath","ts","versionDir","m","i","versionTimestamp","version","raw","getArray","tags","a","articles","filePath","relPath","relative","query","maxResults","queryLower","docs","cachePath","index","buildIndexCached","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","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","cachePath","index","buildIndexCached","bm25Scores","scoreAll","scoreMap","r","matched","i","s","selected","a","b","lines","chars","scope","line","memoryIds","idSet","changed","currentInterval","writeFileSync","now","due","age","content","contentWords","w","mLower","ttlMs","MessageQueue","defaultMode","agentId","channel","chatId","k","mode","callback","q","message","messages","combined","m","key","readFileSync","writeFileSync","appendFileSync","mkdirSync","existsSync","resolve","MAX_PATTERNS","EXTRACTION_MODEL","PATTERN_EXTRACTION_PROMPT","PatternStore","baseDir","resolve","existsSync","mkdirSync","agentId","file","readFileSync","l","p","pattern","entry","appendFileSync","message","limit","patterns","docs","cachePath","index","buildIndexCached","results","scoreAll","s","lines","existing","words","w","pWords","ids","idSet","changed","writeFileSync","a","b","extractPatterns","userMessage","agentResponse","source","store","createProvider","jsonMatch","globalRegistry","setGlobalRegistry","registry","getGlobalRegistry","AgentRegistry","config","log","SessionStore","WikiHub","MemoryStore","PatternStore","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","relevantPatterns","patternContext","skillInjection","loadLocalSkills","getAutoInjectSkills","skills","resumeSessionId","compactResult","quality","lost","d","e","sessionHistory","crossChatContext","soulSessionKey","soulSwitch","detectSoulSwitch","activeSoul","bootstrapFiles","loadBootstrapFiles","bootstrapContext","buildBootstrapContext","contextInput","historyContext","buildAgentContext","response","executeTask","entryId","extractMemories","extractPatterns","error","qm","s","days"]}
@@ -0,0 +1,6 @@
1
+ import{z as e}from"zod";import{readFileSync as m,existsSync as d}from"fs";import{resolve as u}from"path";import{z as t}from"zod";var h=t.enum(["mon","tue","wed","thu","fri","sat","sun"]),b=t.object({days:t.array(h).default(["mon","tue","wed","thu","fri"]),start:t.string().regex(/^\d{2}:\d{2}$/),end:t.string().regex(/^\d{2}:\d{2}$/),lunch:t.object({start:t.string().regex(/^\d{2}:\d{2}$/),end:t.string().regex(/^\d{2}:\d{2}$/)}).optional()}),y=t.object({title:t.string(),responsibilities:t.array(t.string()).default([]),sopPath:t.string().optional(),kpis:t.array(t.string()).default([])}),k=t.object({role:t.string(),reportsTo:t.string().optional(),schedule:b,utilizationTarget:t.number().min(0).max(1).default(.8)}),j=t.object({channel:t.string(),chatId:t.string(),accountId:t.string().optional()}),w=t.discriminatedUnion("type",[t.object({type:t.literal("backlog"),path:t.string().default(".agentx/backlog.md")}),t.object({type:t.literal("gitlab"),projects:t.array(t.string()).default([])}),t.object({type:t.literal("wiki"),path:t.string(),glob:t.string().default("**/*.md")})]),p=t.object({enabled:t.boolean().default(!1),timezone:t.string().default("UTC"),mainChannel:j,workSource:w,roles:t.record(t.string(),y).default({}),orgChart:t.record(t.string(),k).default({}),workTickMinutes:t.number().int().min(1).max(60).default(15),idleQueueThreshold:t.number().int().min(0).default(0)});function S(n){let a=u(n,".env");if(!d(a))return;let r=m(a,"utf-8");for(let o of r.split(`
2
+ `)){let s=o.trim();if(!s||s.startsWith("#"))continue;let l=s.indexOf("=");if(l===-1)continue;let c=s.slice(0,l).trim(),i=s.slice(l+1).trim();process.env[c]||(process.env[c]=i)}}var C=e.object({apiKey:e.string().optional(),defaultModel:e.string().optional(),baseUrl:e.string().optional()}),x=e.object({name:e.string(),workspace:e.string(),tier:e.enum(["claude-code","sdk","orchestrator"]).default("claude-code"),provider:e.string().optional(),model:e.string().optional(),systemPrompt:e.string().optional(),mentions:e.array(e.string()).default([]),maxConcurrent:e.number().default(1),permissionMode:e.string().default("default"),queueMode:e.enum(["collect","followup","drop"]).default("collect"),heartbeat:e.object({enabled:e.boolean().default(!1),intervalMinutes:e.number().default(30),prompt:e.string().default("Check inbox, pending tasks, and system health. Report anything that needs attention."),channel:e.string().default("heartbeat")}).default({})}),v=e.object({token:e.string(),agentBinding:e.string()}),$=e.object({telegram:e.object({enabled:e.boolean().default(!1),accounts:e.record(e.string(),v).default({}),policy:e.object({dm:e.enum(["pair","block"]).default("pair"),group:e.enum(["mention-required","all"]).default("mention-required")}).default({})}).default({}),whatsapp:e.object({enabled:e.boolean().default(!1),sessionDir:e.string().default(".agentx/whatsapp-sessions"),defaultAgent:e.string().optional(),allowFrom:e.array(e.string()).optional(),routes:e.array(e.object({contact:e.string().optional(),group:e.string().optional(),agent:e.string()})).default([])}).default({}),discord:e.object({enabled:e.boolean().default(!1),token:e.string().optional(),agentBinding:e.string().optional()}).default({}),gitlab:e.object({enabled:e.boolean().default(!1),webhookPort:e.number().default(18810),webhookSecret:e.string().optional(),host:e.string().default("https://gitlab.com"),token:e.string().optional(),routes:e.array(e.object({project:e.string(),agent:e.string()})).default([]),agentMappings:e.array(e.object({agentId:e.string(),gitlabUsernames:e.array(e.string()).default([]),keywords:e.array(e.string()).default([]),token:e.string().optional()})).default([])}).default({})}),z=e.object({enabled:e.boolean().default(!0),schedule:e.string(),timezone:e.string().default("UTC"),agent:e.string(),prompt:e.string(),timeout:e.number().default(600),model:e.string().optional(),onError:e.union([e.enum(["log","notify","disable"]),e.array(e.enum(["log","notify","disable"]))]).default("log").transform(n=>Array.isArray(n)?n:[n]),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}),A=e.object({name:e.string(),triggers:e.array(e.object({pattern:e.string(),channel:e.string().optional()})),allowedContacts:e.array(e.string()).optional(),agent:e.string(),prompt:e.string(),schedule:e.string().optional(),timezone:e.string().default("UTC"),notify:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional()}),I=e.object({url:e.string(),name:e.string(),token:e.string().optional()}),E=e.object({enabled:e.boolean().default(!1),peers:e.array(I).default([]),discovery:e.enum(["static","mdns"]).default("static"),healthCheck:e.object({interval:e.number().default(60),timeout:e.number().default(10)}).default({})}),B=e.object({longTaskThreshold:e.number().default(30),destination:e.object({channel:e.string(),chatId:e.string(),accountId:e.string().optional()}).optional(),on:e.object({taskComplete:e.boolean().default(!0),taskError:e.boolean().default(!0),taskQueued:e.boolean().default(!1)}).default({})}).default({}),P=e.object({node:e.object({id:e.string(),name:e.string(),bind:e.string().default("127.0.0.1:18800"),defaultAgent:e.string().optional()}),providers:e.record(e.string(),C).default({}),agents:e.record(e.string(),x).default({}),channels:$.default({}),crons:e.record(e.string(),z).default({}),services:e.record(e.string(),A).default({}),notifications:B,mesh:E.default({}),business:p.optional()});function f(n){if(typeof n=="string")return n.replace(/\$\{(\w+)\}/g,(a,r)=>process.env[r]||"");if(Array.isArray(n))return n.map(f);if(n!==null&&typeof n=="object"){let a={};for(let[r,o]of Object.entries(n))a[r]=f(o);return a}return n}function J(n){let a=n?[n]:[u(process.cwd(),"agentx.json"),u(process.cwd(),".agentx/config.json")];S(process.cwd());let r,o;for(let i of a)if(d(i)){r=m(i,"utf-8"),o=i;break}if(!r||!o)throw new Error(`No config found. Create agentx.json or .agentx/config.json
3
+ Searched: ${a.join(", ")}`);let s;try{s=JSON.parse(r)}catch(i){throw new Error(`Invalid JSON in ${o}: ${i.message}`)}let l=f(s),c=P.safeParse(l);if(!c.success){let i=c.error.issues.map(g=>` ${g.path.join(".")}: ${g.message}`).join(`
4
+ `);throw new Error(`Config validation failed (${o}):
5
+ ${i}`)}return c.data}function q(n){let a=[];for(let[r,o]of Object.entries(n.agents)){if(!d(o.workspace)){a.push(`Agent "${r}": workspace not found at ${o.workspace}`);continue}if(o.tier==="claude-code"){let c=u(o.workspace,".claude");d(c)||a.push(`Agent "${r}": no .claude/ directory in workspace ${o.workspace}. Claude Code native features (hooks, MCP, skills) won't be available.`)}let s=o.provider||"claude",l=n.providers[s];o.tier!=="claude-code"&&(!l||!l.apiKey)&&a.push(`Agent "${r}": provider "${s}" has no API key configured. Set providers.${s}.apiKey in config or use tier "claude-code" for subscription.`)}for(let[r,o]of Object.entries(n.crons))n.agents[o.agent]||a.push(`Cron "${r}": references unknown agent "${o.agent}"`);if(n.channels.telegram.enabled)for(let[r,o]of Object.entries(n.channels.telegram.accounts))n.agents[o.agentBinding]||a.push(`Telegram account "${r}": references unknown agent "${o.agentBinding}"`);return a}export{P as a,J as b,q as c};
6
+ //# sourceMappingURL=chunk-WJ6ZF6EZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/daemon/config.ts","../src/business/config.ts"],"sourcesContent":["import { z } from \"zod\"\nimport { readFileSync, existsSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { businessConfigSchema } from \"@/business/config\"\n\n/**\n * Load .env file into process.env (simple, no dependency).\n */\nfunction loadDotEnv(dir: string): void {\n const envPath = resolve(dir, \".env\")\n if (!existsSync(envPath)) return\n\n const content = readFileSync(envPath, \"utf-8\")\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim()\n if (!trimmed || trimmed.startsWith(\"#\")) continue\n const eqIdx = trimmed.indexOf(\"=\")\n if (eqIdx === -1) continue\n const key = trimmed.slice(0, eqIdx).trim()\n const value = trimmed.slice(eqIdx + 1).trim()\n if (!process.env[key]) {\n process.env[key] = value\n }\n }\n}\n\n// --- Daemon configuration schema & loader ---\n\nconst providerConfigSchema = z.object({\n apiKey: z.string().optional(),\n defaultModel: z.string().optional(),\n baseUrl: z.string().optional(),\n})\n\nconst agentConfigSchema = z.object({\n name: z.string(),\n workspace: z.string(),\n tier: z.enum([\"claude-code\", \"sdk\", \"orchestrator\"]).default(\"claude-code\"),\n provider: z.string().optional(),\n model: z.string().optional(),\n systemPrompt: z.string().optional(),\n mentions: z.array(z.string()).default([]),\n maxConcurrent: z.number().default(1),\n permissionMode: z.string().default(\"default\"),\n queueMode: z.enum([\"collect\", \"followup\", \"drop\"]).default(\"collect\"),\n heartbeat: z.object({\n enabled: z.boolean().default(false),\n intervalMinutes: z.number().default(30),\n prompt: z.string().default(\"Check inbox, pending tasks, and system health. Report anything that needs attention.\"),\n channel: z.string().default(\"heartbeat\"),\n }).default({}),\n})\n\nconst telegramAccountSchema = z.object({\n token: z.string(),\n agentBinding: z.string(),\n})\n\nconst channelsConfigSchema = z.object({\n telegram: z.object({\n enabled: z.boolean().default(false),\n accounts: z.record(z.string(), telegramAccountSchema).default({}),\n policy: z.object({\n dm: z.enum([\"pair\", \"block\"]).default(\"pair\"),\n group: z.enum([\"mention-required\", \"all\"]).default(\"mention-required\"),\n }).default({}),\n }).default({}),\n whatsapp: z.object({\n enabled: z.boolean().default(false),\n sessionDir: z.string().default(\".agentx/whatsapp-sessions\"),\n defaultAgent: z.string().optional(),\n allowFrom: z.array(z.string()).optional(),\n routes: z.array(z.object({\n contact: z.string().optional(),\n group: z.string().optional(),\n agent: z.string(),\n })).default([]),\n }).default({}),\n discord: z.object({\n enabled: z.boolean().default(false),\n token: z.string().optional(),\n agentBinding: z.string().optional(),\n }).default({}),\n gitlab: z.object({\n enabled: z.boolean().default(false),\n webhookPort: z.number().default(18810),\n webhookSecret: z.string().optional(),\n host: z.string().default(\"https://gitlab.com\"),\n token: z.string().optional(),\n routes: z.array(z.object({\n project: z.string(),\n agent: z.string(),\n })).default([]),\n agentMappings: z.array(z.object({\n agentId: z.string(),\n gitlabUsernames: z.array(z.string()).default([]),\n keywords: z.array(z.string()).default([]),\n token: z.string().optional(),\n })).default([]),\n }).default({}),\n})\n\nconst cronJobSchema = z.object({\n enabled: z.boolean().default(true),\n schedule: z.string(),\n timezone: z.string().default(\"UTC\"),\n agent: z.string(),\n prompt: z.string(),\n timeout: z.number().default(600),\n model: z.string().optional(),\n onError: z.union([\n z.enum([\"log\", \"notify\", \"disable\"]),\n z.array(z.enum([\"log\", \"notify\", \"disable\"])),\n ]).default(\"log\").transform(v => Array.isArray(v) ? v : [v]),\n notify: z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n }).optional(),\n})\n\nconst serviceSchema = z.object({\n name: z.string(),\n triggers: z.array(z.object({\n pattern: z.string(),\n channel: z.string().optional(),\n })),\n allowedContacts: z.array(z.string()).optional(),\n agent: z.string(),\n prompt: z.string(),\n schedule: z.string().optional(),\n timezone: z.string().default(\"UTC\"),\n notify: z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n }).optional(),\n})\n\nconst meshPeerSchema = z.object({\n url: z.string(),\n name: z.string(),\n token: z.string().optional(),\n})\n\nconst meshConfigSchema = z.object({\n enabled: z.boolean().default(false),\n peers: z.array(meshPeerSchema).default([]),\n discovery: z.enum([\"static\", \"mdns\"]).default(\"static\"),\n healthCheck: z.object({\n interval: z.number().default(60),\n timeout: z.number().default(10),\n }).default({}),\n})\n\nconst notificationsSchema = z.object({\n /** Send notification when task takes longer than this (seconds). 0 = disabled. */\n longTaskThreshold: z.number().default(30),\n /** Where to send notifications */\n destination: z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n }).optional(),\n /** Notify on these events */\n on: z.object({\n taskComplete: z.boolean().default(true),\n taskError: z.boolean().default(true),\n taskQueued: z.boolean().default(false),\n }).default({}),\n}).default({})\n\nexport const daemonConfigSchema = z.object({\n node: z.object({\n id: z.string(),\n name: z.string(),\n bind: z.string().default(\"127.0.0.1:18800\"),\n /** Default agent for voice/API calls that don't specify one (e.g. Siri) */\n defaultAgent: z.string().optional(),\n }),\n providers: z.record(z.string(), providerConfigSchema).default({}),\n agents: z.record(z.string(), agentConfigSchema).default({}),\n channels: channelsConfigSchema.default({}),\n crons: z.record(z.string(), cronJobSchema).default({}),\n services: z.record(z.string(), serviceSchema).default({}),\n notifications: notificationsSchema,\n mesh: meshConfigSchema.default({}),\n business: businessConfigSchema.optional(),\n})\n\nexport type DaemonConfig = z.infer<typeof daemonConfigSchema>\nexport type AgentDef = z.infer<typeof agentConfigSchema>\nexport type CronJobDef = z.infer<typeof cronJobSchema>\nexport type MeshPeer = z.infer<typeof meshPeerSchema>\n\n/**\n * Expand environment variables in strings: ${VAR_NAME} -> process.env.VAR_NAME\n */\nfunction expandEnvVars(obj: unknown): unknown {\n if (typeof obj === \"string\") {\n return obj.replace(/\\$\\{(\\w+)\\}/g, (_match, name) => process.env[name] || \"\")\n }\n if (Array.isArray(obj)) {\n return obj.map(expandEnvVars)\n }\n if (obj !== null && typeof obj === \"object\") {\n const result: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[key] = expandEnvVars(value)\n }\n return result\n }\n return obj\n}\n\n/**\n * Load daemon config from agentx.json, with env var expansion and validation.\n */\nexport function loadDaemonConfig(configPath?: string): DaemonConfig {\n const paths = configPath\n ? [configPath]\n : [\n resolve(process.cwd(), \"agentx.json\"),\n resolve(process.cwd(), \".agentx/config.json\"),\n ]\n\n // Load .env from same directory as config search\n loadDotEnv(process.cwd())\n\n let raw: string | undefined\n let foundPath: string | undefined\n\n for (const p of paths) {\n if (existsSync(p)) {\n raw = readFileSync(p, \"utf-8\")\n foundPath = p\n break\n }\n }\n\n if (!raw || !foundPath) {\n throw new Error(\n `No config found. Create agentx.json or .agentx/config.json\\n` +\n `Searched: ${paths.join(\", \")}`\n )\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch (e: any) {\n throw new Error(`Invalid JSON in ${foundPath}: ${e.message}`)\n }\n\n // Expand environment variables\n const expanded = expandEnvVars(parsed)\n\n // Validate\n const result = daemonConfigSchema.safeParse(expanded)\n if (!result.success) {\n const issues = result.error.issues\n .map((i) => ` ${i.path.join(\".\")}: ${i.message}`)\n .join(\"\\n\")\n throw new Error(`Config validation failed (${foundPath}):\\n${issues}`)\n }\n\n return result.data\n}\n\n/**\n * Validate agent workspace directories exist and have .claude/ setup.\n */\nexport function validateWorkspaces(config: DaemonConfig): string[] {\n const warnings: string[] = []\n\n for (const [id, agent] of Object.entries(config.agents)) {\n if (!existsSync(agent.workspace)) {\n warnings.push(`Agent \"${id}\": workspace not found at ${agent.workspace}`)\n continue\n }\n\n if (agent.tier === \"claude-code\") {\n const claudeDir = resolve(agent.workspace, \".claude\")\n if (!existsSync(claudeDir)) {\n warnings.push(\n `Agent \"${id}\": no .claude/ directory in workspace ${agent.workspace}. ` +\n `Claude Code native features (hooks, MCP, skills) won't be available.`\n )\n }\n }\n\n // Check provider availability\n const providerName = agent.provider || \"claude\"\n const providerConfig = config.providers[providerName]\n if (agent.tier !== \"claude-code\" && (!providerConfig || !providerConfig.apiKey)) {\n warnings.push(\n `Agent \"${id}\": provider \"${providerName}\" has no API key configured. ` +\n `Set providers.${providerName}.apiKey in config or use tier \"claude-code\" for subscription.`\n )\n }\n }\n\n // Validate cron agent bindings\n for (const [id, cron] of Object.entries(config.crons)) {\n if (!config.agents[cron.agent]) {\n warnings.push(`Cron \"${id}\": references unknown agent \"${cron.agent}\"`)\n }\n }\n\n // Validate channel agent bindings\n if (config.channels.telegram.enabled) {\n for (const [name, account] of Object.entries(config.channels.telegram.accounts)) {\n if (!config.agents[account.agentBinding]) {\n warnings.push(\n `Telegram account \"${name}\": references unknown agent \"${account.agentBinding}\"`\n )\n }\n }\n }\n\n return warnings\n}\n","import { z } from \"zod\"\n\n// --- Business layer configuration schema ---\n// Optional top-level `business` key in agentx.json.\n// When enabled, AgentX simulates a team with roles, schedules, and a work pool.\n\nconst dayEnum = z.enum([\"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\", \"sun\"])\n\nconst scheduleSchema = z.object({\n days: z.array(dayEnum).default([\"mon\", \"tue\", \"wed\", \"thu\", \"fri\"]),\n start: z.string().regex(/^\\d{2}:\\d{2}$/), // \"09:00\"\n end: z.string().regex(/^\\d{2}:\\d{2}$/), // \"17:00\"\n lunch: z.object({\n start: z.string().regex(/^\\d{2}:\\d{2}$/),\n end: z.string().regex(/^\\d{2}:\\d{2}$/),\n }).optional(),\n})\n\nconst roleSchema = z.object({\n title: z.string(),\n responsibilities: z.array(z.string()).default([]),\n sopPath: z.string().optional(),\n kpis: z.array(z.string()).default([]),\n})\n\nconst orgEntrySchema = z.object({\n role: z.string(),\n reportsTo: z.string().optional(),\n schedule: scheduleSchema,\n utilizationTarget: z.number().min(0).max(1).default(0.8),\n})\n\nconst channelRefSchema = z.object({\n channel: z.string(),\n chatId: z.string(),\n accountId: z.string().optional(),\n})\n\nconst workSourceSchema = z.discriminatedUnion(\"type\", [\n z.object({\n type: z.literal(\"backlog\"),\n path: z.string().default(\".agentx/backlog.md\"),\n }),\n z.object({\n type: z.literal(\"gitlab\"),\n projects: z.array(z.string()).default([]), // empty = all configured gitlab projects\n }),\n z.object({\n type: z.literal(\"wiki\"),\n path: z.string(),\n glob: z.string().default(\"**/*.md\"),\n }),\n])\n\nexport const businessConfigSchema = z.object({\n enabled: z.boolean().default(false),\n timezone: z.string().default(\"UTC\"),\n mainChannel: channelRefSchema,\n workSource: workSourceSchema,\n roles: z.record(z.string(), roleSchema).default({}),\n orgChart: z.record(z.string(), orgEntrySchema).default({}),\n /** Work-tick cadence in minutes during business hours. Default 15. */\n workTickMinutes: z.number().int().min(1).max(60).default(15),\n /** Max queue depth for an idle agent before skipping the work tick (avoids piling up). */\n idleQueueThreshold: z.number().int().min(0).default(0),\n})\n\nexport type BusinessConfig = z.infer<typeof businessConfigSchema>\nexport type BusinessRole = z.infer<typeof roleSchema>\nexport type BusinessOrgEntry = z.infer<typeof orgEntrySchema>\nexport type BusinessSchedule = z.infer<typeof scheduleSchema>\nexport type BusinessWorkSource = z.infer<typeof workSourceSchema>\nexport type BusinessChannelRef = z.infer<typeof channelRefSchema>\n"],"mappings":"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","names":["z","readFileSync","existsSync","resolve","z","dayEnum","scheduleSchema","roleSchema","orgEntrySchema","channelRefSchema","workSourceSchema","businessConfigSchema","loadDotEnv","dir","envPath","resolve","existsSync","content","readFileSync","line","trimmed","eqIdx","key","value","providerConfigSchema","z","agentConfigSchema","telegramAccountSchema","channelsConfigSchema","cronJobSchema","v","serviceSchema","meshPeerSchema","meshConfigSchema","notificationsSchema","daemonConfigSchema","businessConfigSchema","expandEnvVars","obj","_match","name","result","loadDaemonConfig","configPath","paths","raw","foundPath","p","parsed","e","expanded","issues","i","validateWorkspaces","config","warnings","id","agent","claudeDir","providerName","providerConfig","cron","account"]}
@@ -0,0 +1,23 @@
1
+ var m="claude-haiku-4-20250514",f=`You are a memory extraction system for an AI agent. Given a conversation exchange, extract facts worth remembering for future conversations across different chat sessions.
2
+
3
+ Extract ONLY facts that would help the agent in FUTURE, DIFFERENT conversations:
4
+ - Credentials, tokens, API keys shared by the user
5
+ - User preferences and instructions ("never do X", "always use Y")
6
+ - Commitments the agent made ("I will deploy by Friday")
7
+ - Relationships ("Anis is the admin", "Nadia handles content")
8
+ - Task state ("GitLab tokens need deploying to clawd-server")
9
+ - Important facts about infrastructure, config, or processes
10
+
11
+ SKIP:
12
+ - Routine greetings, acknowledgments, status updates
13
+ - Information derivable from code or config files
14
+ - Transient conversation flow ("let me check", "here's what I found")
15
+ - Facts already obvious from the agent's system prompt
16
+
17
+ For each fact, output a JSON array:
18
+ [{"category":"fact|secret|preference|commitment|task-state","content":"concise fact, 1-2 sentences","keywords":["keyword1","keyword2"]}]
19
+
20
+ If nothing worth remembering, output: []`;async function h(t,s,a,n,r){if(s.length<20&&a.length<50)return;let{createProvider:i}=await import("./providers-G3WZ4RVJ.js"),c=(await i("claude").generate([{role:"system",content:f},{role:"user",content:`${n.sender} (via ${n.channel}): ${s}
21
+
22
+ Agent: ${a}`}],{model:m,maxTokens:512})).content.trim().match(/\[[\s\S]*\]/);if(!c)return;let o=JSON.parse(c[0]);if(!Array.isArray(o)||o.length===0)return;let d=new Date().toISOString().slice(0,10);for(let e of o)r.hasSimilar(t,e.content)||r.addMemory(t,{agentId:t,category:e.category,content:e.content,keywords:e.keywords||[],source:{...n,date:d},expiresAt:e.category==="task-state"?new Date(Date.now()+7*24*60*60*1e3).toISOString():void 0});Math.random()<.02&&r.prune(t)}export{h as a};
23
+ //# sourceMappingURL=chunk-ZRYBSI5G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agents/memory-extract.ts"],"sourcesContent":["import type { MemoryStore } from \"./memory-store\"\n\n// --- Haiku-powered memory extraction ---\n// Fire-and-forget after each agent response.\n// Extracts memorable facts and writes them to the persistent store.\n\nconst EXTRACTION_MODEL = \"claude-haiku-4-20250514\"\n\nconst EXTRACTION_PROMPT = `You are a memory extraction system for an AI agent. Given a conversation exchange, extract facts worth remembering for future conversations across different chat sessions.\n\nExtract ONLY facts that would help the agent in FUTURE, DIFFERENT conversations:\n- Credentials, tokens, API keys shared by the user\n- User preferences and instructions (\"never do X\", \"always use Y\")\n- Commitments the agent made (\"I will deploy by Friday\")\n- Relationships (\"Anis is the admin\", \"Nadia handles content\")\n- Task state (\"GitLab tokens need deploying to clawd-server\")\n- Important facts about infrastructure, config, or processes\n\nSKIP:\n- Routine greetings, acknowledgments, status updates\n- Information derivable from code or config files\n- Transient conversation flow (\"let me check\", \"here's what I found\")\n- Facts already obvious from the agent's system prompt\n\nFor each fact, output a JSON array:\n[{\"category\":\"fact|secret|preference|commitment|task-state\",\"content\":\"concise fact, 1-2 sentences\",\"keywords\":[\"keyword1\",\"keyword2\"]}]\n\nIf nothing worth remembering, output: []`\n\nexport async function extractMemories(\n agentId: string,\n userMessage: string,\n agentResponse: string,\n source: { channel: string; chatId: string; sender: string },\n store: MemoryStore,\n): Promise<void> {\n // Skip very short exchanges (unlikely to contain memorable facts)\n if (userMessage.length < 20 && agentResponse.length < 50) return\n\n const { createProvider } = await import(\"@/agent/providers\")\n const provider = createProvider(\"claude\")\n\n const result = await provider.generate(\n [\n { role: \"system\", content: EXTRACTION_PROMPT },\n {\n role: \"user\",\n content: `${source.sender} (via ${source.channel}): ${userMessage}\\n\\nAgent: ${agentResponse}`,\n },\n ],\n { model: EXTRACTION_MODEL, maxTokens: 512 },\n )\n\n // Parse JSON array from response\n const content = result.content.trim()\n const jsonMatch = content.match(/\\[[\\s\\S]*\\]/)\n if (!jsonMatch) return\n\n const facts = JSON.parse(jsonMatch[0]) as Array<{\n category: string\n content: string\n keywords: string[]\n }>\n\n if (!Array.isArray(facts) || facts.length === 0) return\n\n const date = new Date().toISOString().slice(0, 10)\n\n for (const fact of facts) {\n // Skip duplicates\n if (store.hasSimilar(agentId, fact.content)) continue\n\n store.addMemory(agentId, {\n agentId,\n category: fact.category as any,\n content: fact.content,\n keywords: fact.keywords || [],\n source: { ...source, date },\n expiresAt: fact.category === \"task-state\"\n ? new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()\n : undefined,\n })\n }\n\n // Prune occasionally (every ~50 calls, probabilistic)\n if (Math.random() < 0.02) {\n store.prune(agentId)\n }\n}\n"],"mappings":"AAMA,IAAMA,EAAmB,0BAEnBC,EAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0CAqB1B,eAAsBC,EACpBC,EACAC,EACAC,EACAC,EACAC,EACe,CAEf,GAAIH,EAAY,OAAS,IAAMC,EAAc,OAAS,GAAI,OAE1D,GAAM,CAAE,eAAAG,CAAe,EAAI,KAAM,QAAO,yBAAmB,EAgBrDC,GAbS,MAFED,EAAe,QAAQ,EAEV,SAC5B,CACE,CAAE,KAAM,SAAU,QAASP,CAAkB,EAC7C,CACE,KAAM,OACN,QAAS,GAAGK,EAAO,eAAeA,EAAO,aAAaF;AAAA;AAAA,SAAyBC,GACjF,CACF,EACA,CAAE,MAAOL,EAAkB,UAAW,GAAI,CAC5C,GAGuB,QAAQ,KAAK,EACV,MAAM,aAAa,EAC7C,GAAI,CAACS,EAAW,OAEhB,IAAMC,EAAQ,KAAK,MAAMD,EAAU,CAAC,CAAC,EAMrC,GAAI,CAAC,MAAM,QAAQC,CAAK,GAAKA,EAAM,SAAW,EAAG,OAEjD,IAAMC,EAAO,IAAI,KAAK,EAAE,YAAY,EAAE,MAAM,EAAG,EAAE,EAEjD,QAAWC,KAAQF,EAEbH,EAAM,WAAWJ,EAASS,EAAK,OAAO,GAE1CL,EAAM,UAAUJ,EAAS,CACvB,QAAAA,EACA,SAAUS,EAAK,SACf,QAASA,EAAK,QACd,SAAUA,EAAK,UAAY,CAAC,EAC5B,OAAQ,CAAE,GAAGN,EAAQ,KAAAK,CAAK,EAC1B,UAAWC,EAAK,WAAa,aACzB,IAAI,KAAK,KAAK,IAAI,EAAI,EAAI,GAAK,GAAK,GAAK,GAAI,EAAE,YAAY,EAC3D,MACN,CAAC,EAIC,KAAK,OAAO,EAAI,KAClBL,EAAM,MAAMJ,CAAO,CAEvB","names":["EXTRACTION_MODEL","EXTRACTION_PROMPT","extractMemories","agentId","userMessage","agentResponse","source","store","createProvider","jsonMatch","facts","date","fact"]}