@agentmemory/agentmemory 0.8.1 → 0.8.5

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools-registry-B9EXJvIf.mjs","names":[],"sources":["../src/config.ts","../src/version.ts","../src/mcp/tools-registry.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type {\n AgentMemoryConfig,\n ProviderConfig,\n EmbeddingConfig,\n FallbackConfig,\n ClaudeBridgeConfig,\n TeamConfig,\n} from \"./types.js\";\n\nfunction safeParseInt(value: string | undefined, fallback: number): number {\n if (!value) return fallback;\n const parsed = parseInt(value, 10);\n return Number.isNaN(parsed) ? fallback : parsed;\n}\n\nconst DATA_DIR = join(homedir(), \".agentmemory\");\nconst ENV_FILE = join(DATA_DIR, \".env\");\n\nfunction loadEnvFile(): Record<string, string> {\n if (!existsSync(ENV_FILE)) return {};\n const content = readFileSync(ENV_FILE, \"utf-8\");\n const vars: Record<string, string> = {};\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 let val = trimmed.slice(eqIdx + 1).trim();\n if (\n (val.startsWith('\"') && val.endsWith('\"')) ||\n (val.startsWith(\"'\") && val.endsWith(\"'\"))\n ) {\n val = val.slice(1, -1);\n }\n vars[key] = val;\n }\n return vars;\n}\n\nfunction detectProvider(env: Record<string, string>): ProviderConfig {\n const maxTokens = parseInt(env[\"MAX_TOKENS\"] || \"4096\", 10);\n\n // MiniMax: Anthropic-compatible API, requires raw fetch to avoid SDK stainless headers\n if (env[\"MINIMAX_API_KEY\"]) {\n return {\n provider: \"minimax\",\n model: env[\"MINIMAX_MODEL\"] || \"MiniMax-M2.7\",\n maxTokens,\n };\n }\n\n if (env[\"ANTHROPIC_API_KEY\"]) {\n return {\n provider: \"anthropic\",\n model: env[\"ANTHROPIC_MODEL\"] || \"claude-sonnet-4-20250514\",\n maxTokens,\n baseURL: env[\"ANTHROPIC_BASE_URL\"],\n };\n }\n if (env[\"GEMINI_API_KEY\"]) {\n return {\n provider: \"gemini\",\n model: env[\"GEMINI_MODEL\"] || \"gemini-2.0-flash\",\n maxTokens,\n };\n }\n if (env[\"OPENROUTER_API_KEY\"]) {\n return {\n provider: \"openrouter\",\n model: env[\"OPENROUTER_MODEL\"] || \"anthropic/claude-sonnet-4-20250514\",\n maxTokens,\n };\n }\n return {\n provider: \"agent-sdk\",\n model: \"claude-sonnet-4-20250514\",\n maxTokens: 4096,\n };\n}\n\nexport function loadConfig(): AgentMemoryConfig {\n const env = getMergedEnv();\n\n const provider = detectProvider(env);\n\n return {\n engineUrl: env[\"III_ENGINE_URL\"] || \"ws://localhost:49134\",\n restPort: parseInt(env[\"III_REST_PORT\"] || \"3111\", 10) || 3111,\n streamsPort: parseInt(env[\"III_STREAMS_PORT\"] || \"3112\", 10) || 3112,\n provider,\n tokenBudget: safeParseInt(env[\"TOKEN_BUDGET\"], 2000),\n maxObservationsPerSession: safeParseInt(env[\"MAX_OBS_PER_SESSION\"], 500),\n compressionModel: provider.model,\n dataDir: DATA_DIR,\n };\n}\n\nfunction getMergedEnv(\n overrides?: Record<string, string>,\n): Record<string, string> {\n const fileEnv = loadEnvFile();\n return { ...fileEnv, ...process.env, ...overrides } as Record<string, string>;\n}\n\nexport function getEnvVar(key: string): string | undefined {\n return getMergedEnv()[key];\n}\n\nexport function loadEmbeddingConfig(): EmbeddingConfig {\n const env = getMergedEnv();\n let bm25Weight = parseFloat(env[\"BM25_WEIGHT\"] || \"0.4\");\n let vectorWeight = parseFloat(env[\"VECTOR_WEIGHT\"] || \"0.6\");\n bm25Weight =\n isNaN(bm25Weight) || bm25Weight < 0 ? 0.4 : Math.min(bm25Weight, 1);\n vectorWeight =\n isNaN(vectorWeight) || vectorWeight < 0 ? 0.6 : Math.min(vectorWeight, 1);\n return {\n provider: env[\"EMBEDDING_PROVIDER\"] || undefined,\n bm25Weight,\n vectorWeight,\n };\n}\n\nexport function detectEmbeddingProvider(\n env?: Record<string, string>,\n): string | null {\n const source = env ?? getMergedEnv();\n const forced = source[\"EMBEDDING_PROVIDER\"];\n if (forced) return forced;\n\n if (source[\"GEMINI_API_KEY\"]) return \"gemini\";\n if (source[\"OPENAI_API_KEY\"]) return \"openai\";\n if (source[\"VOYAGE_API_KEY\"]) return \"voyage\";\n if (source[\"COHERE_API_KEY\"]) return \"cohere\";\n if (source[\"OPENROUTER_API_KEY\"]) return \"openrouter\";\n return null;\n}\n\nexport function loadClaudeBridgeConfig(): ClaudeBridgeConfig {\n const env = getMergedEnv();\n const enabled = env[\"CLAUDE_MEMORY_BRIDGE\"] === \"true\";\n const projectPath = env[\"CLAUDE_PROJECT_PATH\"] || \"\";\n const lineBudget = safeParseInt(env[\"CLAUDE_MEMORY_LINE_BUDGET\"], 200);\n let memoryFilePath = \"\";\n if (enabled && projectPath) {\n const safePath = projectPath.replace(/[/\\\\]/g, \"-\").replace(/^-/, \"\");\n memoryFilePath = join(\n homedir(),\n \".claude\",\n \"projects\",\n safePath,\n \"memory\",\n \"MEMORY.md\",\n );\n }\n return { enabled, projectPath, memoryFilePath, lineBudget };\n}\n\nexport function loadTeamConfig(): TeamConfig | null {\n const env = getMergedEnv();\n const teamId = env[\"TEAM_ID\"];\n const userId = env[\"USER_ID\"];\n if (!teamId || !userId) return null;\n const mode = env[\"TEAM_MODE\"] === \"shared\" ? \"shared\" : \"private\";\n return { teamId, userId, mode };\n}\n\nexport function loadSnapshotConfig(): {\n enabled: boolean;\n interval: number;\n dir: string;\n} {\n const env = getMergedEnv();\n return {\n enabled: env[\"SNAPSHOT_ENABLED\"] === \"true\",\n interval: safeParseInt(env[\"SNAPSHOT_INTERVAL\"], 3600),\n dir: env[\"SNAPSHOT_DIR\"] || join(homedir(), \".agentmemory\", \"snapshots\"),\n };\n}\n\nexport function isGraphExtractionEnabled(): boolean {\n return getMergedEnv()[\"GRAPH_EXTRACTION_ENABLED\"] === \"true\";\n}\n\nexport function getGraphBatchSize(): number {\n return safeParseInt(getMergedEnv()[\"GRAPH_EXTRACTION_BATCH_SIZE\"], 10);\n}\n\nexport function isConsolidationEnabled(): boolean {\n return getMergedEnv()[\"CONSOLIDATION_ENABLED\"] === \"true\";\n}\n\nexport function getConsolidationDecayDays(): number {\n return safeParseInt(getMergedEnv()[\"CONSOLIDATION_DECAY_DAYS\"], 30);\n}\n\nexport function isStandaloneMcp(): boolean {\n return getMergedEnv()[\"STANDALONE_MCP\"] === \"true\";\n}\n\nexport function getStandalonePersistPath(): string {\n const env = getMergedEnv();\n return (\n env[\"STANDALONE_PERSIST_PATH\"] ||\n join(homedir(), \".agentmemory\", \"standalone.json\")\n );\n}\n\nconst VALID_PROVIDERS = new Set([\n \"anthropic\",\n \"gemini\",\n \"openrouter\",\n \"agent-sdk\",\n \"minimax\",\n]);\n\nexport function loadFallbackConfig(): FallbackConfig {\n const env = getMergedEnv();\n const raw = env[\"FALLBACK_PROVIDERS\"] || \"\";\n const providers = raw\n .split(\",\")\n .map((p) => p.trim())\n .filter(\n (p): p is FallbackConfig[\"providers\"][number] =>\n Boolean(p) && VALID_PROVIDERS.has(p),\n );\n return { providers };\n}\n","export const VERSION: \"0.3.0\" | \"0.4.0\" | \"0.5.0\" | \"0.6.0\" | \"0.6.1\" | \"0.7.0\" | \"0.7.2\" | \"0.7.3\" | \"0.7.4\" | \"0.7.5\" | \"0.7.6\" | \"0.8.1\" | \"0.8.2\" | \"0.8.3\" | \"0.8.4\" | \"0.8.5\" = \"0.8.5\";\n","export type McpToolDef = {\n name: string;\n description: string;\n inputSchema: {\n type: \"object\";\n properties: Record<string, { type: string; description: string }>;\n required?: string[];\n };\n};\n\nexport const CORE_TOOLS: McpToolDef[] = [\n {\n name: \"memory_recall\",\n description:\n \"Search past session observations for relevant context. Use when you need to recall what happened in previous sessions, find past decisions, or look up how a file was modified before.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: {\n type: \"string\",\n description: \"Search query (keywords, file names, concepts)\",\n },\n limit: {\n type: \"number\",\n description: \"Max results to return (default 10)\",\n },\n },\n required: [\"query\"],\n },\n },\n {\n name: \"memory_save\",\n description:\n \"Explicitly save an important insight, decision, or pattern to long-term memory.\",\n inputSchema: {\n type: \"object\",\n properties: {\n content: {\n type: \"string\",\n description: \"The insight or decision to remember\",\n },\n type: {\n type: \"string\",\n description:\n \"Memory type: pattern, preference, architecture, bug, workflow, or fact\",\n },\n concepts: {\n type: \"string\",\n description: \"Comma-separated key concepts\",\n },\n files: {\n type: \"string\",\n description: \"Comma-separated relevant file paths\",\n },\n },\n required: [\"content\"],\n },\n },\n {\n name: \"memory_file_history\",\n description: \"Get past observations about specific files.\",\n inputSchema: {\n type: \"object\",\n properties: {\n files: { type: \"string\", description: \"Comma-separated file paths\" },\n sessionId: {\n type: \"string\",\n description: \"Current session ID to exclude\",\n },\n },\n required: [\"files\"],\n },\n },\n {\n name: \"memory_patterns\",\n description: \"Detect recurring patterns across sessions.\",\n inputSchema: {\n type: \"object\",\n properties: {\n project: { type: \"string\", description: \"Project path to analyze\" },\n },\n },\n },\n {\n name: \"memory_sessions\",\n description:\n \"List recent sessions with their status and observation counts.\",\n inputSchema: { type: \"object\", properties: {} },\n },\n {\n name: \"memory_smart_search\",\n description: \"Hybrid semantic+keyword search with progressive disclosure.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Search query\" },\n expandIds: {\n type: \"string\",\n description: \"Comma-separated observation IDs to expand\",\n },\n limit: { type: \"number\", description: \"Max results (default 10)\" },\n },\n required: [\"query\"],\n },\n },\n {\n name: \"memory_timeline\",\n description: \"Chronological observations around an anchor point.\",\n inputSchema: {\n type: \"object\",\n properties: {\n anchor: {\n type: \"string\",\n description: \"Anchor point: ISO date or keyword\",\n },\n project: { type: \"string\", description: \"Filter by project path\" },\n before: {\n type: \"number\",\n description: \"Observations before anchor (default 5)\",\n },\n after: {\n type: \"number\",\n description: \"Observations after anchor (default 5)\",\n },\n },\n required: [\"anchor\"],\n },\n },\n {\n name: \"memory_profile\",\n description: \"User/project profile with top concepts and file patterns.\",\n inputSchema: {\n type: \"object\",\n properties: {\n project: { type: \"string\", description: \"Project path\" },\n refresh: {\n type: \"string\",\n description: \"Set to 'true' to force rebuild\",\n },\n },\n required: [\"project\"],\n },\n },\n {\n name: \"memory_export\",\n description: \"Export all memory data as JSON.\",\n inputSchema: { type: \"object\", properties: {} },\n },\n {\n name: \"memory_relations\",\n description: \"Query the memory relationship graph.\",\n inputSchema: {\n type: \"object\",\n properties: {\n memoryId: {\n type: \"string\",\n description: \"Memory ID to find relations for\",\n },\n maxHops: {\n type: \"number\",\n description: \"Max traversal depth (default 2)\",\n },\n minConfidence: {\n type: \"number\",\n description: \"Min confidence (0-1, default 0)\",\n },\n },\n required: [\"memoryId\"],\n },\n },\n];\n\nexport const V040_TOOLS: McpToolDef[] = [\n {\n name: \"memory_claude_bridge_sync\",\n description:\n \"Sync memory state to/from Claude Code's native MEMORY.md file.\",\n inputSchema: {\n type: \"object\",\n properties: {\n direction: {\n type: \"string\",\n description:\n \"'read' to import from MEMORY.md, 'write' to export to MEMORY.md\",\n },\n },\n required: [\"direction\"],\n },\n },\n {\n name: \"memory_graph_query\",\n description: \"Query the knowledge graph for entities and relationships.\",\n inputSchema: {\n type: \"object\",\n properties: {\n startNodeId: {\n type: \"string\",\n description: \"Starting node ID for traversal\",\n },\n nodeType: { type: \"string\", description: \"Filter by node type\" },\n maxDepth: {\n type: \"number\",\n description: \"Max BFS depth (default 3, max 5)\",\n },\n query: { type: \"string\", description: \"Search nodes by name\" },\n },\n },\n },\n {\n name: \"memory_consolidate\",\n description:\n \"Run the 4-tier memory consolidation pipeline (working -> episodic -> semantic -> procedural).\",\n inputSchema: {\n type: \"object\",\n properties: {\n tier: {\n type: \"string\",\n description: \"Target tier: episodic, semantic, or procedural\",\n },\n },\n },\n },\n {\n name: \"memory_team_share\",\n description: \"Share a memory or observation with team members.\",\n inputSchema: {\n type: \"object\",\n properties: {\n itemId: {\n type: \"string\",\n description: \"ID of memory or observation to share\",\n },\n itemType: {\n type: \"string\",\n description: \"Type: observation, memory, or pattern\",\n },\n },\n required: [\"itemId\", \"itemType\"],\n },\n },\n {\n name: \"memory_team_feed\",\n description: \"Get recent shared items from all team members.\",\n inputSchema: {\n type: \"object\",\n properties: {\n limit: { type: \"number\", description: \"Max items (default 20)\" },\n },\n },\n },\n {\n name: \"memory_audit\",\n description: \"View the audit trail of memory operations.\",\n inputSchema: {\n type: \"object\",\n properties: {\n operation: { type: \"string\", description: \"Filter by operation type\" },\n limit: { type: \"number\", description: \"Max entries (default 50)\" },\n },\n },\n },\n {\n name: \"memory_governance_delete\",\n description: \"Delete specific memories with audit trail.\",\n inputSchema: {\n type: \"object\",\n properties: {\n memoryIds: {\n type: \"string\",\n description: \"Comma-separated memory IDs to delete\",\n },\n reason: { type: \"string\", description: \"Reason for deletion\" },\n },\n required: [\"memoryIds\"],\n },\n },\n {\n name: \"memory_snapshot_create\",\n description: \"Create a git-versioned snapshot of current memory state.\",\n inputSchema: {\n type: \"object\",\n properties: {\n message: { type: \"string\", description: \"Snapshot description\" },\n },\n },\n },\n];\n\nexport const V050_TOOLS: McpToolDef[] = [\n {\n name: \"memory_action_create\",\n description:\n \"Create an actionable work item with typed dependencies. Actions track what agents need to do and how work items relate to each other.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: { type: \"string\", description: \"Action title\" },\n description: {\n type: \"string\",\n description: \"Detailed description of the work\",\n },\n priority: {\n type: \"number\",\n description: \"Priority 1-10 (10 highest)\",\n },\n project: { type: \"string\", description: \"Project path\" },\n tags: {\n type: \"string\",\n description: \"Comma-separated tags\",\n },\n parentId: {\n type: \"string\",\n description: \"Parent action ID for hierarchical actions\",\n },\n requires: {\n type: \"string\",\n description:\n \"Comma-separated action IDs that must complete before this\",\n },\n },\n required: [\"title\"],\n },\n },\n {\n name: \"memory_action_update\",\n description:\n \"Update an action's status, priority, or details. Set status to 'done' to complete it and unblock dependent actions.\",\n inputSchema: {\n type: \"object\",\n properties: {\n actionId: { type: \"string\", description: \"Action ID to update\" },\n status: {\n type: \"string\",\n description: \"New status: pending, active, done, blocked, cancelled\",\n },\n result: {\n type: \"string\",\n description: \"Outcome description (when completing)\",\n },\n priority: { type: \"number\", description: \"New priority 1-10\" },\n },\n required: [\"actionId\"],\n },\n },\n {\n name: \"memory_frontier\",\n description:\n \"Get all unblocked actions ranked by priority and urgency. Returns the frontier of actionable work with no unsatisfied dependencies.\",\n inputSchema: {\n type: \"object\",\n properties: {\n project: { type: \"string\", description: \"Filter by project\" },\n agentId: {\n type: \"string\",\n description: \"Agent ID to check lease conflicts\",\n },\n limit: { type: \"number\", description: \"Max results (default 20)\" },\n },\n },\n },\n {\n name: \"memory_next\",\n description:\n \"Get the single most important next action to work on. Combines dependency resolution, priority, and recency into a score.\",\n inputSchema: {\n type: \"object\",\n properties: {\n project: { type: \"string\", description: \"Filter by project\" },\n agentId: { type: \"string\", description: \"Current agent ID\" },\n },\n },\n },\n {\n name: \"memory_lease\",\n description:\n \"Acquire, release, or renew an exclusive lease on an action. Prevents multiple agents from working on the same thing.\",\n inputSchema: {\n type: \"object\",\n properties: {\n actionId: { type: \"string\", description: \"Action ID\" },\n agentId: { type: \"string\", description: \"Agent claiming the action\" },\n operation: {\n type: \"string\",\n description: \"acquire, release, or renew\",\n },\n result: {\n type: \"string\",\n description: \"Result when releasing (marks action done)\",\n },\n ttlMs: {\n type: \"number\",\n description: \"Lease duration in ms (default 10min, max 1hr)\",\n },\n },\n required: [\"actionId\", \"agentId\", \"operation\"],\n },\n },\n {\n name: \"memory_routine_run\",\n description:\n \"Instantiate a frozen workflow routine, creating actions for each step with proper dependencies.\",\n inputSchema: {\n type: \"object\",\n properties: {\n routineId: { type: \"string\", description: \"Routine template ID\" },\n project: { type: \"string\", description: \"Project context\" },\n initiatedBy: { type: \"string\", description: \"Agent starting the run\" },\n },\n required: [\"routineId\"],\n },\n },\n {\n name: \"memory_signal_send\",\n description:\n \"Send a message to another agent or broadcast. Supports threading, typed messages, and TTL expiration.\",\n inputSchema: {\n type: \"object\",\n properties: {\n from: { type: \"string\", description: \"Sender agent ID\" },\n to: {\n type: \"string\",\n description: \"Recipient agent ID (omit for broadcast)\",\n },\n content: { type: \"string\", description: \"Message content\" },\n type: {\n type: \"string\",\n description: \"Message type: info, request, response, alert, handoff\",\n },\n replyTo: {\n type: \"string\",\n description: \"Signal ID to reply to (auto-threads)\",\n },\n },\n required: [\"from\", \"content\"],\n },\n },\n {\n name: \"memory_signal_read\",\n description:\n \"Read messages for an agent. Marks delivered messages as read.\",\n inputSchema: {\n type: \"object\",\n properties: {\n agentId: { type: \"string\", description: \"Agent to read messages for\" },\n unreadOnly: {\n type: \"string\",\n description: \"Set to 'true' for unread only\",\n },\n threadId: {\n type: \"string\",\n description: \"Filter by conversation thread\",\n },\n limit: { type: \"number\", description: \"Max messages (default 50)\" },\n },\n required: [\"agentId\"],\n },\n },\n {\n name: \"memory_checkpoint\",\n description:\n \"Create or resolve an external checkpoint (CI result, approval, deploy status) that gates action progress.\",\n inputSchema: {\n type: \"object\",\n properties: {\n operation: {\n type: \"string\",\n description: \"create, resolve, or list\",\n },\n name: { type: \"string\", description: \"Checkpoint name (for create)\" },\n checkpointId: {\n type: \"string\",\n description: \"Checkpoint ID (for resolve)\",\n },\n status: {\n type: \"string\",\n description: \"passed or failed (for resolve)\",\n },\n type: {\n type: \"string\",\n description: \"Checkpoint type: ci, approval, deploy, external, timer\",\n },\n linkedActionIds: {\n type: \"string\",\n description:\n \"Comma-separated action IDs this checkpoint gates (for create)\",\n },\n },\n required: [\"operation\"],\n },\n },\n {\n name: \"memory_mesh_sync\",\n description:\n \"Sync memories and actions with peer agentmemory instances for multi-agent collaboration.\",\n inputSchema: {\n type: \"object\",\n properties: {\n peerId: {\n type: \"string\",\n description: \"Specific peer ID (omit for all)\",\n },\n direction: {\n type: \"string\",\n description: \"push, pull, or both (default both)\",\n },\n },\n },\n },\n];\n\nexport const V051_TOOLS: McpToolDef[] = [\n {\n name: \"memory_sentinel_create\",\n description:\n \"Create an event-driven sentinel that watches for conditions (webhook, timer, threshold, pattern, approval) and auto-unblocks gated actions when triggered.\",\n inputSchema: {\n type: \"object\",\n properties: {\n name: { type: \"string\", description: \"Sentinel name\" },\n type: {\n type: \"string\",\n description: \"Type: webhook, timer, threshold, pattern, approval, custom\",\n },\n config: {\n type: \"string\",\n description: \"JSON config (timer: {durationMs}, threshold: {metric,operator,value}, pattern: {pattern}, webhook: {path})\",\n },\n linkedActionIds: {\n type: \"string\",\n description: \"Comma-separated action IDs to gate\",\n },\n expiresInMs: { type: \"number\", description: \"Auto-expire after ms\" },\n },\n required: [\"name\", \"type\"],\n },\n },\n {\n name: \"memory_sentinel_trigger\",\n description:\n \"Externally fire a sentinel, providing an optional result payload. Unblocks any gated actions.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sentinelId: { type: \"string\", description: \"Sentinel ID to trigger\" },\n result: { type: \"string\", description: \"JSON result payload\" },\n },\n required: [\"sentinelId\"],\n },\n },\n {\n name: \"memory_sketch_create\",\n description:\n \"Create an ephemeral action graph for exploratory work. Auto-expires after TTL. Can be promoted to permanent actions or discarded.\",\n inputSchema: {\n type: \"object\",\n properties: {\n title: { type: \"string\", description: \"Sketch title\" },\n description: { type: \"string\", description: \"What this sketch explores\" },\n expiresInMs: { type: \"number\", description: \"TTL in ms (default 1 hour)\" },\n project: { type: \"string\", description: \"Project context\" },\n },\n required: [\"title\"],\n },\n },\n {\n name: \"memory_sketch_promote\",\n description:\n \"Promote a sketch's ephemeral actions to permanent actions. Makes the exploratory work official.\",\n inputSchema: {\n type: \"object\",\n properties: {\n sketchId: { type: \"string\", description: \"Sketch ID to promote\" },\n project: { type: \"string\", description: \"Override project for promoted actions\" },\n },\n required: [\"sketchId\"],\n },\n },\n {\n name: \"memory_crystallize\",\n description:\n \"Compress completed action chains into compact crystal digests using LLM summarization. Extracts narrative, key outcomes, files affected, and lessons.\",\n inputSchema: {\n type: \"object\",\n properties: {\n actionIds: {\n type: \"string\",\n description: \"Comma-separated completed action IDs to crystallize\",\n },\n project: { type: \"string\", description: \"Project context\" },\n sessionId: { type: \"string\", description: \"Session context\" },\n },\n required: [\"actionIds\"],\n },\n },\n {\n name: \"memory_diagnose\",\n description:\n \"Run health checks across all subsystems (actions, leases, sentinels, sketches, signals, sessions, memories, mesh). Identifies stuck, orphaned, and inconsistent state.\",\n inputSchema: {\n type: \"object\",\n properties: {\n categories: {\n type: \"string\",\n description: \"Comma-separated categories to check (default all)\",\n },\n },\n },\n },\n {\n name: \"memory_heal\",\n description:\n \"Auto-fix all fixable issues found by diagnostics. Unblocks stuck actions, expires stale leases, cleans up orphaned data.\",\n inputSchema: {\n type: \"object\",\n properties: {\n categories: {\n type: \"string\",\n description: \"Comma-separated categories to heal (default all)\",\n },\n dryRun: {\n type: \"string\",\n description: \"Set to 'true' for dry run (report but don't fix)\",\n },\n },\n },\n },\n {\n name: \"memory_facet_tag\",\n description:\n \"Attach a structured tag (dimension:value) to an action, memory, or observation for multi-dimensional categorization.\",\n inputSchema: {\n type: \"object\",\n properties: {\n targetId: { type: \"string\", description: \"ID of the target to tag\" },\n targetType: {\n type: \"string\",\n description: \"Type: action, memory, or observation\",\n },\n dimension: { type: \"string\", description: \"Tag dimension (e.g., priority, team, status)\" },\n value: { type: \"string\", description: \"Tag value (e.g., urgent, backend, reviewed)\" },\n },\n required: [\"targetId\", \"targetType\", \"dimension\", \"value\"],\n },\n },\n {\n name: \"memory_facet_query\",\n description:\n \"Query targets by facet tags with AND/OR logic. Find all actions tagged priority:urgent AND team:backend.\",\n inputSchema: {\n type: \"object\",\n properties: {\n matchAll: {\n type: \"string\",\n description: \"Comma-separated dimension:value pairs (AND logic)\",\n },\n matchAny: {\n type: \"string\",\n description: \"Comma-separated dimension:value pairs (OR logic)\",\n },\n targetType: {\n type: \"string\",\n description: \"Filter by type: action, memory, or observation\",\n },\n },\n },\n },\n];\n\nexport const V061_TOOLS: McpToolDef[] = [\n {\n name: \"memory_verify\",\n description:\n \"Verify a memory or observation by tracing its citation chain back to source observations and session context. Returns provenance information including confidence scores.\",\n inputSchema: {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n description: \"Memory ID or observation ID to verify\",\n },\n },\n required: [\"id\"],\n },\n },\n];\n\nexport const V070_TOOLS: McpToolDef[] = [\n {\n name: \"memory_lesson_save\",\n description:\n \"Save a lesson learned from this session. Lessons have confidence scores that strengthen when reinforced and decay when not used. Duplicate content auto-strengthens the existing lesson.\",\n inputSchema: {\n type: \"object\",\n properties: {\n content: {\n type: \"string\",\n description: \"The lesson learned (what worked, what to avoid, when to use X approach)\",\n },\n context: {\n type: \"string\",\n description: \"When/where this lesson applies\",\n },\n confidence: {\n type: \"number\",\n description: \"Initial confidence 0.0-1.0 (default 0.5)\",\n },\n project: { type: \"string\", description: \"Project this lesson is about\" },\n tags: { type: \"string\", description: \"Comma-separated tags\" },\n },\n required: [\"content\"],\n },\n },\n {\n name: \"memory_lesson_recall\",\n description:\n \"Search lessons by query. Returns lessons sorted by confidence and recency. Use to check what the agent has learned before making decisions.\",\n inputSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", description: \"Search query\" },\n project: { type: \"string\", description: \"Filter by project\" },\n minConfidence: {\n type: \"number\",\n description: \"Minimum confidence threshold (default 0.1)\",\n },\n limit: { type: \"number\", description: \"Max results (default 10)\" },\n },\n required: [\"query\"],\n },\n },\n {\n name: \"memory_obsidian_export\",\n description:\n \"Export memories, lessons, and crystals as Obsidian-compatible Markdown files with YAML frontmatter and wikilinks for graph view.\",\n inputSchema: {\n type: \"object\",\n properties: {\n vaultDir: {\n type: \"string\",\n description: \"Output directory (default ~/.agentmemory/vault/)\",\n },\n types: {\n type: \"string\",\n description: \"Comma-separated types to export: memories,lessons,crystals,sessions (default all)\",\n },\n },\n },\n },\n];\n\nexport const V073_TOOLS: McpToolDef[] = [\n {\n name: \"memory_reflect\",\n description:\n \"Traverse the knowledge graph, group related memories by concept clusters, and synthesize higher-order insights via LLM. Returns new and reinforced insights.\",\n inputSchema: {\n type: \"object\",\n properties: {\n project: { type: \"string\", description: \"Filter by project\" },\n maxClusters: {\n type: \"number\",\n description: \"Max concept clusters to process (default 10, max 20)\",\n },\n },\n },\n },\n {\n name: \"memory_insight_list\",\n description:\n \"List synthesized insights — higher-order observations derived from patterns across memories, lessons, and crystals.\",\n inputSchema: {\n type: \"object\",\n properties: {\n project: { type: \"string\", description: \"Filter by project\" },\n minConfidence: {\n type: \"number\",\n description: \"Minimum confidence threshold (default 0)\",\n },\n limit: { type: \"number\", description: \"Max results (default 50)\" },\n },\n },\n },\n];\n\nconst ESSENTIAL_TOOLS = new Set([\n \"memory_save\",\n \"memory_recall\",\n \"memory_consolidate\",\n \"memory_smart_search\",\n \"memory_sessions\",\n \"memory_diagnose\",\n \"memory_lesson_save\",\n \"memory_reflect\",\n]);\n\nexport function getAllTools(): McpToolDef[] {\n return [...CORE_TOOLS, ...V040_TOOLS, ...V050_TOOLS, ...V051_TOOLS, ...V061_TOOLS, ...V070_TOOLS, ...V073_TOOLS];\n}\n\nexport function getVisibleTools(): McpToolDef[] {\n const mode = process.env[\"AGENTMEMORY_TOOLS\"] || \"core\";\n if (mode === \"all\") return getAllTools();\n return getAllTools().filter((t) => ESSENTIAL_TOOLS.has(t.name));\n}\n"],"mappings":"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;CACF;AAED,MAAa,aAA2B;CACtC;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,WAAW;IACT,MAAM;IACN,aACE;IACH,EACF;GACD,UAAU,CAAC,YAAY;GACxB;EACF;CACD;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,aAAa;KACX,MAAM;KACN,aAAa;KACd;IACD,UAAU;KAAE,MAAM;KAAU,aAAa;KAAuB;IAChE,UAAU;KACR,MAAM;KACN,aAAa;KACd;IACD,OAAO;KAAE,MAAM;KAAU,aAAa;KAAwB;IAC/D;GACF;EACF;CACD;EACE,MAAM;EACN,aACE;EACF,aAAa;GACX,MAAM;GACN,YAAY,EACV,MAAM;IACJ,MAAM;IACN,aAAa;IACd,EACF;GACF;EACF;CACD;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,QAAQ;KACN,MAAM;KACN,aAAa;KACd;IACD,UAAU;KACR,MAAM;KACN,aAAa;KACd;IACF;GACD,UAAU,CAAC,UAAU,WAAW;GACjC;EACF;CACD;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY,EACV,OAAO;IAAE,MAAM;IAAU,aAAa;IAA0B,EACjE;GACF;EACF;CACD;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,WAAW;KAAE,MAAM;KAAU,aAAa;KAA4B;IACtE,OAAO;KAAE,MAAM;KAAU,aAAa;KAA4B;IACnE;GACF;EACF;CACD;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY;IACV,WAAW;KACT,MAAM;KACN,aAAa;KACd;IACD,QAAQ;KAAE,MAAM;KAAU,aAAa;KAAuB;IAC/D;GACD,UAAU,CAAC,YAAY;GACxB;EACF;CACD;EACE,MAAM;EACN,aAAa;EACb,aAAa;GACX,MAAM;GACN,YAAY,EACV,SAAS;IAAE,MAAM;IAAU,aAAa;IAAwB,EACjE;GACF;EACF;CACF;AAED,MAAa,aAA2B;CACtC;EACE,MAAM;EACN,aAC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"}
@@ -765,7 +765,7 @@
765
765
  </div>
766
766
  <div class="header-right">
767
767
  <span class="dateline" id="dateline"></span>
768
- <button id="theme-toggle" class="btn" style="font-size:9px;padding:3px 10px;letter-spacing:0.1em;margin-right:8px;" onclick="toggleTheme()">DARK</button>
768
+ <button id="theme-toggle" class="btn" style="font-size:9px;padding:3px 10px;letter-spacing:0.1em;margin-right:8px;" data-action="toggle-theme">DARK</button>
769
769
  <span id="ws-status" class="ws-status disconnected">live updates off</span>
770
770
  </div>
771
771
  </div>
@@ -800,7 +800,7 @@
800
800
  <div class="modal" id="modal"></div>
801
801
  </div>
802
802
 
803
- <script>
803
+ <script nonce="__AGENTMEMORY_VIEWER_NONCE__">
804
804
  var params = new URLSearchParams(window.location.search);
805
805
  var viewerPort = params.get('port') || window.location.port || '3113';
806
806
  var iiiPort = parseInt(viewerPort);
@@ -1026,7 +1026,12 @@
1026
1026
  var estInjected = d.sessions.length * tokenBudget;
1027
1027
  var savings = estFull > 0 ? Math.round((1 - estInjected / Math.max(estFull, 1)) * 100) : 0;
1028
1028
  if (savings < 0) savings = 0;
1029
- html += '<div class="stat-card"><div class="label">Token Savings</div><div class="value">' + savings + '%</div><div class="sub">~' + estInjected.toLocaleString() + ' vs ~' + estFull.toLocaleString() + ' full (budget: ' + tokenBudget + ')</div></div>';
1029
+ var tokensSaved = Math.max(0, estFull - estInjected);
1030
+ // Rate: $0.30 per 1K tokens (mid-tier model baseline)
1031
+ var costDollars = tokensSaved / 1000 * 0.3;
1032
+ var costCents = Math.round(costDollars * 100);
1033
+ var costStr = costCents >= 100 ? '$' + (costCents / 100).toFixed(2) : costCents + 'ct';
1034
+ html += '<div class="stat-card"><div class="label">Token Savings</div><div class="value">' + savings + '%</div><div class="sub">~' + tokensSaved.toLocaleString() + ' tokens · ' + costStr + ' saved</div></div>';
1030
1035
  html += '</div>';
1031
1036
 
1032
1037
  if (snap.memory || snap.cpu) {
@@ -1216,7 +1221,7 @@
1216
1221
  html += '</div>';
1217
1222
  }
1218
1223
 
1219
- html += '<div style="text-align:center;margin-top:20px;"><button class="btn btn-primary" onclick="refreshDashboard()">Refresh</button>';
1224
+ html += '<div style="text-align:center;margin-top:20px;"><button class="btn btn-primary" data-action="refresh-dashboard">Refresh</button>';
1220
1225
  html += '<span style="font-size:10px;color:var(--ink-faint);margin-left:10px;font-family:var(--font-mono);text-transform:uppercase;letter-spacing:0.08em;">Auto-refresh 30s</span></div>';
1221
1226
 
1222
1227
  el.innerHTML = html;
@@ -1238,7 +1243,7 @@
1238
1243
 
1239
1244
  async function loadGraph() {
1240
1245
  var el = document.getElementById('view-graph');
1241
- el.innerHTML = '<div class="graph-container"><div class="graph-canvas-wrap"><canvas id="graph-canvas"></canvas><div class="graph-controls"><button title="Zoom In" onclick="zoomGraph(1)">+</button><button title="Zoom Out" onclick="zoomGraph(-1)">&minus;</button><div class="ctrl-divider"></div><button title="Recenter" onclick="recenterGraph()">⌖</button></div><div class="graph-tooltip" id="graph-tooltip"></div></div><div class="graph-sidebar" id="graph-sidebar"></div></div>';
1246
+ el.innerHTML = '<div class="graph-container"><div class="graph-canvas-wrap"><canvas id="graph-canvas"></canvas><div class="graph-controls"><button title="Zoom In" data-action="zoom-graph" data-dir="1">+</button><button title="Zoom Out" data-action="zoom-graph" data-dir="-1">&minus;</button><div class="ctrl-divider"></div><button title="Recenter" data-action="recenter-graph">⌖</button></div><div class="graph-tooltip" id="graph-tooltip"></div></div><div class="graph-sidebar" id="graph-sidebar"></div></div>';
1242
1247
 
1243
1248
  var results = await Promise.all([
1244
1249
  apiPost('graph/query', {}),
@@ -1315,7 +1320,7 @@
1315
1320
  });
1316
1321
  html += '</div>';
1317
1322
 
1318
- html += '<button class="btn" style="margin-top:14px;width:100%;font-size:11px;padding:8px;letter-spacing:0.06em;transition:all 0.15s ease;" onclick="rebuildGraph()" onmouseover="this.style.background=\'var(--ink)\';this.style.color=\'var(--bg)\'" onmouseout="this.style.background=\'\';this.style.color=\'\'">↻ Rebuild Graph</button>';
1323
+ html += '<button class="btn" style="margin-top:14px;width:100%;font-size:11px;padding:8px;letter-spacing:0.06em;transition:all 0.15s ease;" data-action="rebuild-graph">↻ Rebuild Graph</button>';
1319
1324
  html += '<div id="selected-node-panel"></div>';
1320
1325
  sb.innerHTML = html;
1321
1326
 
@@ -1510,7 +1515,7 @@
1510
1515
  }
1511
1516
  var conns = graphSim.edges.filter(function(e) { return e.sourceNodeId === simNode.id || e.targetNodeId === simNode.id; }).length;
1512
1517
  html += '<div class="prop">Connections: ' + conns + '</div>';
1513
- html += '<button class="btn btn-primary" style="margin-top:8px;width:100%;" onclick="expandNode(\'' + esc(simNode.id) + '\')">Expand neighbors</button>';
1518
+ html += '<button class="btn btn-primary" style="margin-top:8px;width:100%;" data-action="expand-node" data-node-id="' + esc(simNode.id) + '">Expand neighbors</button>';
1514
1519
  html += '</div>';
1515
1520
  panel.innerHTML = html;
1516
1521
  }
@@ -1929,7 +1934,7 @@
1929
1934
  html += '<td><div class="strength-bar"><div class="fill" style="width:' + strength + '%;background:' + barColor + '"></div></div> <span style="font-size:10px;color:var(--ink-faint);font-family:var(--font-mono);">' + strength + '%</span></td>';
1930
1935
  html += '<td style="color:var(--ink-muted);font-family:var(--font-mono);font-size:12px;">v' + (m.version || 1) + '</td>';
1931
1936
  html += '<td style="font-size:11px;color:var(--ink-faint);font-family:var(--font-mono);">' + esc(formatTime(m.updatedAt)) + '</td>';
1932
- html += '<td><button class="btn btn-danger" style="font-size:9px;padding:2px 8px;" onclick="deleteMemory(\'' + esc(m.id) + '\',\'' + esc((m.title || '').replace(/'/g, '')) + '\')">Delete</button></td>';
1937
+ html += '<td><button class="btn btn-danger" style="font-size:9px;padding:2px 8px;" data-action="delete-memory" data-memory-id="' + esc(m.id) + '" data-memory-title="' + esc(m.title || '') + '">Delete</button></td>';
1933
1938
  html += '</tr>';
1934
1939
  });
1935
1940
  html += '</table>';
@@ -1956,7 +1961,7 @@
1956
1961
  function deleteMemory(id, title) {
1957
1962
  var modal = document.getElementById('modal');
1958
1963
  var overlay = document.getElementById('modal-overlay');
1959
- modal.innerHTML = '<h3>Delete Memory</h3><p>Are you sure you want to delete "' + esc(title) + '"? This action cannot be undone.</p><div class="modal-actions"><button class="btn" onclick="closeModal()">Cancel</button><button class="btn btn-danger" onclick="confirmDeleteMemory(\'' + esc(id) + '\')">Delete</button></div>';
1964
+ modal.innerHTML = '<h3>Delete Memory</h3><p>Are you sure you want to delete "' + esc(title) + '"? This action cannot be undone.</p><div class="modal-actions"><button class="btn" data-action="close-modal">Cancel</button><button class="btn btn-danger" data-action="confirm-delete-memory" data-memory-id="' + esc(id) + '">Delete</button></div>';
1960
1965
  overlay.classList.add('open');
1961
1966
  }
1962
1967
 
@@ -2060,10 +2065,10 @@
2060
2065
  var totalPages = Math.ceil(filtered.length / pageSize);
2061
2066
 
2062
2067
  var html = '<div class="type-chips">';
2063
- html += '<span class="type-chip' + (!tlTypeFilter ? ' active' : '') + '" onclick="setTlTypeFilter(\'\')">All (' + obs.length + ')</span>';
2068
+ html += '<span class="type-chip' + (!tlTypeFilter ? ' active' : '') + '" data-action="timeline-filter" data-type-filter="">All (' + obs.length + ')</span>';
2064
2069
  typeList.forEach(function(t) {
2065
2070
  var color = OBS_TYPE_COLORS[t] || '#666666';
2066
- html += '<span class="type-chip' + (tlTypeFilter === t ? ' active' : '') + '" onclick="setTlTypeFilter(\'' + esc(t) + '\')" style="' + (tlTypeFilter === t ? 'background:' + color + ';border-color:' + color + ';' : 'border-color:' + color + ';color:' + color + ';') + '">' + esc(t.replace(/_/g, ' ')) + ' (' + typeCounts[t] + ')</span>';
2071
+ html += '<span class="type-chip' + (tlTypeFilter === t ? ' active' : '') + '" data-action="timeline-filter" data-type-filter="' + esc(t) + '" style="' + (tlTypeFilter === t ? 'background:' + color + ';border-color:' + color + ';' : 'border-color:' + color + ';color:' + color + ';') + '">' + esc(t.replace(/_/g, ' ')) + ' (' + typeCounts[t] + ')</span>';
2067
2072
  });
2068
2073
  html += '</div>';
2069
2074
 
@@ -2175,9 +2180,9 @@
2175
2180
 
2176
2181
  if (totalPages > 1) {
2177
2182
  html += '<div class="pagination">';
2178
- if (page > 0) html += '<button class="btn" onclick="tlPage(' + (page - 1) + ')">Prev</button>';
2183
+ if (page > 0) html += '<button class="btn" data-action="timeline-page" data-page="' + (page - 1) + '">Prev</button>';
2179
2184
  html += '<span style="color:var(--ink-faint);font-size:12px;padding:6px;font-family:var(--font-mono);">Page ' + (page + 1) + ' of ' + totalPages + ' (' + filtered.length + ' total)</span>';
2180
- if (page < totalPages - 1) html += '<button class="btn" onclick="tlPage(' + (page + 1) + ')">Next</button>';
2185
+ if (page < totalPages - 1) html += '<button class="btn" data-action="timeline-page" data-page="' + (page + 1) + '">Next</button>';
2181
2186
  html += '</div>';
2182
2187
  }
2183
2188
 
@@ -2354,7 +2359,7 @@
2354
2359
  items.forEach(function(s) {
2355
2360
  var statusBadge = s.status === 'active' ? 'badge-green' : s.status === 'completed' ? 'badge-blue' : 'badge-muted';
2356
2361
  var selected = state.sessions.selectedId === s.id;
2357
- html += '<div class="session-item' + (selected ? ' selected' : '') + '" onclick="selectSession(\'' + esc(s.id) + '\')">';
2362
+ html += '<div class="session-item' + (selected ? ' selected' : '') + '" data-action="select-session" data-session-id="' + esc(s.id) + '">';
2358
2363
  html += '<div class="session-top"><span class="session-project">' + esc(s.project ? s.project.split('/').pop() : 'Unknown') + '</span>';
2359
2364
  html += '<span class="badge ' + statusBadge + '">' + esc(s.status) + '</span></div>';
2360
2365
  html += '<div class="session-meta">' + esc(s.id.slice(0, 12)) + ' &middot; ' + esc(formatTime(s.startedAt));
@@ -2394,9 +2399,9 @@
2394
2399
 
2395
2400
  html += '<div style="margin-top:16px;display:flex;gap:8px;">';
2396
2401
  if (s.status === 'active') {
2397
- html += '<button class="btn btn-danger" onclick="endSession(\'' + esc(s.id) + '\')">End Session</button>';
2402
+ html += '<button class="btn btn-danger" data-action="end-session" data-session-id="' + esc(s.id) + '">End Session</button>';
2398
2403
  }
2399
- html += '<button class="btn btn-primary" onclick="summarizeSession(\'' + esc(s.id) + '\')">Summarize</button>';
2404
+ html += '<button class="btn btn-primary" data-action="summarize-session" data-session-id="' + esc(s.id) + '">Summarize</button>';
2400
2405
  html += '</div></div>';
2401
2406
  panel.innerHTML = html;
2402
2407
  }
@@ -2407,8 +2412,8 @@
2407
2412
  loadSessions();
2408
2413
  }
2409
2414
 
2410
- async function summarizeSession(id) {
2411
- var btn = event.target;
2415
+ async function summarizeSession(id, btn) {
2416
+ if (!btn) return;
2412
2417
  btn.textContent = 'Summarizing...';
2413
2418
  btn.disabled = true;
2414
2419
  await apiPost('summarize', { sessionId: id });
@@ -2639,7 +2644,7 @@
2639
2644
  html += '<span class="badge ' + badgeClass + '">' + esc(a.operation) + '</span>';
2640
2645
  html += '<span style="font-size:12px;color:var(--ink-muted);font-family:var(--font-mono);">' + esc(a.functionId || '') + '</span>';
2641
2646
  html += '<span style="font-size:10px;color:var(--ink-faint);margin-left:auto;font-family:var(--font-mono);">' + esc(formatTime(a.timestamp)) + '</span>';
2642
- html += '<button class="btn" style="font-size:9px;padding:1px 6px;margin-left:8px;" onclick="toggleAuditDetail(' + idx + ')">&#9660;</button>';
2647
+ html += '<button class="btn" style="font-size:9px;padding:1px 6px;margin-left:8px;" data-action="toggle-audit" data-audit-index="' + idx + '">&#9660;</button>';
2643
2648
  html += '</div>';
2644
2649
  if (a.targetIds && a.targetIds.length) {
2645
2650
  html += '<div style="font-size:10px;color:var(--ink-faint);font-family:var(--font-mono);">' + a.targetIds.length + ' target(s): ' + esc(a.targetIds.slice(0, 3).join(', ')) + (a.targetIds.length > 3 ? '...' : '') + '</div>';
@@ -2876,6 +2881,83 @@
2876
2881
  switchTab(e.target.dataset.tab);
2877
2882
  }
2878
2883
  });
2884
+ document.addEventListener('click', function(e) {
2885
+ if (!(e.target instanceof Element)) return;
2886
+ var target = e.target.closest('[data-action]');
2887
+ if (!target) return;
2888
+ var action = target.getAttribute('data-action');
2889
+ if (!action) return;
2890
+
2891
+ if (action === 'toggle-theme') {
2892
+ toggleTheme();
2893
+ return;
2894
+ }
2895
+ if (action === 'refresh-dashboard') {
2896
+ refreshDashboard();
2897
+ return;
2898
+ }
2899
+ if (action === 'zoom-graph') {
2900
+ zoomGraph(parseInt(target.getAttribute('data-dir') || '0', 10));
2901
+ return;
2902
+ }
2903
+ if (action === 'recenter-graph') {
2904
+ recenterGraph();
2905
+ return;
2906
+ }
2907
+ if (action === 'rebuild-graph') {
2908
+ rebuildGraph();
2909
+ return;
2910
+ }
2911
+ if (action === 'expand-node') {
2912
+ var nodeId = target.getAttribute('data-node-id');
2913
+ if (nodeId) expandNode(nodeId);
2914
+ return;
2915
+ }
2916
+ if (action === 'delete-memory') {
2917
+ deleteMemory(
2918
+ target.getAttribute('data-memory-id') || '',
2919
+ target.getAttribute('data-memory-title') || '',
2920
+ );
2921
+ return;
2922
+ }
2923
+ if (action === 'close-modal') {
2924
+ closeModal();
2925
+ return;
2926
+ }
2927
+ if (action === 'confirm-delete-memory') {
2928
+ var memoryId = target.getAttribute('data-memory-id');
2929
+ if (memoryId) confirmDeleteMemory(memoryId);
2930
+ return;
2931
+ }
2932
+ if (action === 'timeline-filter') {
2933
+ setTlTypeFilter(target.getAttribute('data-type-filter') || '');
2934
+ return;
2935
+ }
2936
+ if (action === 'timeline-page') {
2937
+ var page = parseInt(target.getAttribute('data-page') || '', 10);
2938
+ if (!Number.isNaN(page)) tlPage(page);
2939
+ return;
2940
+ }
2941
+ if (action === 'select-session') {
2942
+ var sessionId = target.getAttribute('data-session-id');
2943
+ if (sessionId) selectSession(sessionId);
2944
+ return;
2945
+ }
2946
+ if (action === 'end-session') {
2947
+ var endSessionId = target.getAttribute('data-session-id');
2948
+ if (endSessionId) endSession(endSessionId);
2949
+ return;
2950
+ }
2951
+ if (action === 'summarize-session') {
2952
+ var summarizeSessionId = target.getAttribute('data-session-id');
2953
+ if (summarizeSessionId) summarizeSession(summarizeSessionId, target);
2954
+ return;
2955
+ }
2956
+ if (action === 'toggle-audit') {
2957
+ var auditIndex = parseInt(target.getAttribute('data-audit-index') || '', 10);
2958
+ if (!Number.isNaN(auditIndex)) toggleAuditDetail(auditIndex);
2959
+ }
2960
+ });
2879
2961
  document.getElementById('modal-overlay').addEventListener('click', function(e) {
2880
2962
  if (e.target === this) closeModal();
2881
2963
  });
@@ -2,13 +2,13 @@ services:
2
2
  iii-engine:
3
3
  image: iiidev/iii:latest
4
4
  ports:
5
- - "49134:49134"
6
- - "3111:3111"
7
- - "3112:3112"
8
- - "9464:9464"
5
+ - "127.0.0.1:49134:49134"
6
+ - "127.0.0.1:3111:3111"
7
+ - "127.0.0.1:3112:3112"
8
+ - "127.0.0.1:9464:9464"
9
9
  volumes:
10
10
  - iii-data:/data
11
- - ./iii-config.yaml:/app/config.yaml:ro
11
+ - ./iii-config.docker.yaml:/app/config.yaml:ro
12
12
  restart: unless-stopped
13
13
 
14
14
  volumes:
package/iii-config.yaml CHANGED
@@ -10,7 +10,7 @@ modules:
10
10
  - class: modules::api::RestApiModule
11
11
  config:
12
12
  port: 3111
13
- host: 0.0.0.0
13
+ host: 127.0.0.1
14
14
  default_timeout: 180000
15
15
  cors:
16
16
  allowed_origins: ["http://localhost:3111", "http://localhost:3113", "http://127.0.0.1:3111", "http://127.0.0.1:3113"]
@@ -34,7 +34,7 @@ modules:
34
34
  - class: modules::stream::StreamModule
35
35
  config:
36
36
  port: 3112
37
- host: 0.0.0.0
37
+ host: 127.0.0.1
38
38
 
39
39
  - class: modules::observability::OtelModule
40
40
  config:
package/package.json CHANGED
@@ -1,16 +1,23 @@
1
1
  {
2
2
  "name": "@agentmemory/agentmemory",
3
- "version": "0.8.1",
3
+ "version": "0.8.5",
4
4
  "description": "Persistent memory for AI coding agents, powered by iii-engine's three primitives",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
7
7
  "types": "dist/index.d.mts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.mts",
11
+ "import": "./dist/index.mjs"
12
+ },
13
+ "./dist/standalone.mjs": "./dist/standalone.mjs",
14
+ "./package.json": "./package.json"
15
+ },
8
16
  "bin": {
9
- "agentmemory": "dist/cli.mjs",
10
- "agentmemory-mcp": "dist/standalone.mjs"
17
+ "agentmemory": "dist/cli.mjs"
11
18
  },
12
19
  "scripts": {
13
- "build": "tsdown && (cp iii-config.yaml dist/ 2>/dev/null || true) && (cp docker-compose.yml dist/ 2>/dev/null || true) && mkdir -p dist/viewer && cp src/viewer/index.html dist/viewer/",
20
+ "build": "tsdown && (cp iii-config.yaml dist/ 2>/dev/null || true) && (cp iii-config.docker.yaml dist/ 2>/dev/null || true) && (cp docker-compose.yml dist/ 2>/dev/null || true) && mkdir -p dist/viewer && cp src/viewer/index.html dist/viewer/",
14
21
  "dev": "tsx src/index.ts",
15
22
  "start": "node dist/cli.mjs",
16
23
  "migrate": "node dist/functions/migrate.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentmemory",
3
- "version": "0.8.1",
3
+ "version": "0.8.5",
4
4
  "description": "Persistent memory for AI coding agents -- captures tool usage, compresses via LLM, injects context into future sessions. 12 hooks, 43 MCP tools, 4 skills, real-time viewer.",
5
5
  "author": {
6
6
  "name": "Rohit Ghumare",