diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 92f42979..76c9051e 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -10,7 +10,7 @@ "plugins": [ { "name": "claude-mem", - "version": "4.3.3", + "version": "4.3.4", "source": "./plugin", "description": "Persistent memory system for Claude Code - context compression across sessions" } diff --git a/CLAUDE.md b/CLAUDE.md index 2833ddcf..c3caf699 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ Claude-mem is a persistent memory compression system that preserves context across Claude Code sessions. It automatically captures tool usage observations, processes them through the Claude Agent SDK, and makes summaries available to future sessions. -**Current Version**: 4.3.3 +**Current Version**: 4.3.4 **License**: AGPL-3.0 **Author**: Alex Newman (@thedotmack) @@ -189,6 +189,36 @@ Tool Execution → Hook Capture → Worker Processing → AI Compression → Dat Search Query → MCP Server → SessionSearch → FTS5 Query → Results with Citations ``` +### Usage Tracking + +Claude-mem automatically tracks SDK usage metrics to JSONL files for cost analysis: + +**Location**: `~/.claude-mem/usage-logs/usage-YYYY-MM-DD.jsonl` + +**Captured Metrics**: +- Token counts (input, output, cache creation, cache read) +- Total cost in USD per API call +- Duration metrics (total time and API time) +- Number of turns per session +- Session and project attribution +- Model information + +**Analysis Tools**: +```bash +# Analyze today's usage +npm run usage:today + +# Analyze specific date +npm run usage:analyze 2025-11-03 +``` + +The analysis script provides: +- Total cost and token usage +- Cache hit rates and savings +- Cost breakdowns by project +- Cost breakdowns by model +- Average cost per API call + ## Development ### Directory Structure @@ -281,10 +311,22 @@ This approach is especially valuable when: For detailed version history and changelog, see [CHANGELOG.md](CHANGELOG.md). -**Current Version**: 4.3.3 +**Current Version**: 4.3.4 ### Recent Highlights +#### v4.3.4 (2025-11-01) +**Breaking Changes**: None (patch version) + +**Fixes**: +- Fixed SessionStart hooks running on session resume (plugin/hooks/hooks.json:4) +- Added matcher configuration to only run SessionStart hooks on startup, clear, or compact events +- Prevents unnecessary hook execution and improves performance on session resume + +**Technical Details**: +- Modified: plugin/hooks/hooks.json:4 (added `"matcher": "startup|clear|compact"`) +- Impact: Hooks now skip execution when resuming existing sessions + #### v4.3.3 (2025-10-27) **Breaking Changes**: None (patch version) diff --git a/README.md b/README.md index bf0b182f..2efeb60b 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Node - + Mentioned in Awesome Claude Code

diff --git a/context/claude-code/agent-sdk-cost-tracking.md b/context/claude-code/agent-sdk-cost-tracking.md new file mode 100644 index 00000000..4d36074f --- /dev/null +++ b/context/claude-code/agent-sdk-cost-tracking.md @@ -0,0 +1,61 @@ + For tracking costs and tokens in your Agent SDK plugin, you have built-in programmatic access to usage data through the SDK itself[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking). + +## Agent SDK Cost Tracking + +The Claude Agent SDK provides detailed token usage information for each interaction[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking). Here's how to track it: + +**TypeScript:** +```typescript +import { query } from "@anthropic-ai/claude-agent-sdk"; + +const result = await query({ + prompt: "Your task here", + options: { + onMessage: (message) => { + if (message.type === 'assistant' && message.usage) { + console.log(`Message ID: ${message.id}`); + console.log(`Usage:`, message.usage); + } + } + } +}); +``` +[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking) + +The final `result` message contains the total cumulative usage from all steps in the conversation[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking): + +```typescript +console.log("Total usage:", result.usage); +console.log("Total cost:", result.usage.total_cost_usd); +``` +[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking) + +## Important: Avoid Double-Counting + +When Claude executes tools in parallel, multiple assistant messages may share the same ID and usage data[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking). You should only charge once per unique message ID[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking): + +```typescript +const processedMessageIds = new Set(); + +onMessage: (message) => { + if (message.type === 'assistant' && message.usage) { + // Skip if already processed + if (processedMessageIds.has(message.id)) { + return; + } + + processedMessageIds.add(message.id); + // Record usage here + } +} +``` +[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking) + +## Usage Fields + +Each usage object contains[(1)](https://docs.claude.com/en/api/agent-sdk/cost-tracking): +- `input_tokens`: Base input tokens processed +- `output_tokens`: Tokens generated in the response +- `cache_creation_input_tokens`: Tokens used to create cache entries +- `cache_read_input_tokens`: Tokens read from cache +- `total_cost_usd`: Total cost in USD (only in result message) diff --git a/docs/usage/getting-started.mdx b/docs/usage/getting-started.mdx index 4f36e9ba..20b516ea 100644 --- a/docs/usage/getting-started.mdx +++ b/docs/usage/getting-started.mdx @@ -11,9 +11,9 @@ Claude-Mem works automatically once installed. No manual intervention required! ### The Full Cycle -1. **Start Claude Code** - Context from last 3 sessions appears automatically +1. **Start Claude Code** - Context from last 10 sessions appears automatically 2. **Work normally** - Every tool execution is captured -3. **Stop Claude** - Summary is generated and saved +3. **Claude finishes responding** - Stop hook automatically generates and saves a summary 4. **Next session** - Previous work appears in context ### What Gets Captured @@ -42,7 +42,7 @@ The worker service processes tool observations and extracts: ### Session Summaries -When you stop Claude (or a session ends), a summary is generated with: +When Claude finishes responding (triggering the Stop hook), a summary is automatically generated with: - **Request** - What you asked for - **Investigated** - What Claude explored @@ -159,7 +159,7 @@ Context injection uses three-tier verbosity for efficient token usage: This ensures you get maximum detail for recent work while still having context from older sessions. -## Multi-Prompt Sessions +## Multi-Prompt Sessions & `/clear` Behavior Claude-Mem supports sessions that span multiple user prompts: @@ -167,7 +167,15 @@ Claude-Mem supports sessions that span multiple user prompts: - **prompt_number**: Identifies specific prompt within session - **Session continuity**: Observations and summaries link across prompts -When you use `/clear`, the session doesn't end - it continues with a new prompt number. This preserves context across conversation restarts. +### Important Note About `/clear` + +When you use `/clear`, the session doesn't end - it continues with a new prompt number. This means: + +- ✅ **Context is re-injected** from recent sessions (SessionStart hook fires with `source: "clear"`) +- ✅ **Observations are still being captured** and added to the current session +- ✅ **A summary will be generated** when Claude finishes responding (Stop hook fires) + +The `/clear` command clears the conversation context visible to Claude AND re-injects fresh context from recent sessions, while the underlying session continues tracking observations. ## Next Steps diff --git a/package-lock.json b/package-lock.json index a54062bf..a23710f2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "claude-mem", - "version": "4.2.10", + "version": "4.3.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "claude-mem", - "version": "4.2.10", + "version": "4.3.4", "license": "AGPL-3.0", "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.1.27", @@ -15,14 +15,14 @@ "express": "^4.18.2", "glob": "^11.0.3", "handlebars": "^4.7.8", - "pm2": "^5.3.0", + "pm2": "^6.0.13", "zod-to-json-schema": "^3.24.6" }, "devDependencies": { "@types/better-sqlite3": "^7.6.8", "@types/express": "^4.17.21", "@types/node": "^20.0.0", - "esbuild": "^0.20.0", + "esbuild": "^0.25.12", "tsx": "^4.20.6", "typescript": "^5.3.0" }, @@ -51,9 +51,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -64,13 +64,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -81,13 +81,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -98,13 +98,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -115,13 +115,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -132,13 +132,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -149,13 +149,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -166,13 +166,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -183,13 +183,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -200,13 +200,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -217,13 +217,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -234,13 +234,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -251,13 +251,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -268,13 +268,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -285,13 +285,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -302,13 +302,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -319,13 +319,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -336,13 +336,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.11.tgz", - "integrity": "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], @@ -357,9 +357,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -370,13 +370,13 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.11.tgz", - "integrity": "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], @@ -391,9 +391,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -404,13 +404,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.11.tgz", - "integrity": "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", "cpu": [ "arm64" ], @@ -425,9 +425,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -438,13 +438,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -455,13 +455,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -472,13 +472,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -489,7 +489,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@img/sharp-darwin-arm64": { @@ -1092,9 +1092,9 @@ } }, "node_modules/@pm2/agent": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.0.4.tgz", - "integrity": "sha512-n7WYvvTJhHLS2oBb1PjOtgLpMhgImOq8sXkPBw6smeg9LJBWZjiEgPKOpR8mn9UJZsB5P3W4V/MyvNnp31LKeA==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@pm2/agent/-/agent-2.1.1.tgz", + "integrity": "sha512-0V9ckHWd/HSC8BgAbZSoq8KXUG81X97nSkAxmhKDhmF8vanyaoc1YXwc2KVkbWz82Rg4gjd2n9qiT3i7bdvGrQ==", "license": "AGPL-3.0", "dependencies": { "async": "~3.2.0", @@ -1102,44 +1102,15 @@ "dayjs": "~1.8.24", "debug": "~4.3.1", "eventemitter2": "~5.0.1", - "fast-json-patch": "^3.0.0-1", + "fast-json-patch": "^3.1.0", "fclone": "~1.0.11", - "nssocket": "0.6.0", "pm2-axon": "~4.0.1", "pm2-axon-rpc": "~0.7.0", - "proxy-agent": "~6.3.0", + "proxy-agent": "~6.4.0", "semver": "~7.5.0", "ws": "~7.5.10" } }, - "node_modules/@pm2/agent/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@pm2/agent/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/@pm2/agent/node_modules/dayjs": { "version": "1.8.36", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.36.tgz", @@ -1196,10 +1167,22 @@ "node": ">=10" } }, + "node_modules/@pm2/blessed": { + "version": "0.1.81", + "resolved": "https://registry.npmjs.org/@pm2/blessed/-/blessed-0.1.81.tgz", + "integrity": "sha512-ZcNHqQjMuNRcQ7Z1zJbFIQZO/BDKV3KbiTckWdfbUaYhj7uNmUwb+FbdDWSCkvxNr9dBJQwvV17o6QBkAvgO0g==", + "license": "MIT", + "bin": { + "blessed": "bin/tput.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/@pm2/io": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@pm2/io/-/io-6.0.1.tgz", - "integrity": "sha512-KiA+shC6sULQAr9mGZ1pg+6KVW9MF8NpG99x26Lf/082/Qy8qsTCtnJy+HQReW1A9Rdf0C/404cz0RZGZro+IA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@pm2/io/-/io-6.1.0.tgz", + "integrity": "sha512-IxHuYURa3+FQ6BKePlgChZkqABUKFYH6Bwbw7V/pWU1pP6iR1sCI26l7P9ThUEB385ruZn/tZS3CXDUF5IA1NQ==", "license": "Apache-2", "dependencies": { "async": "~2.6.1", @@ -1588,6 +1571,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/ansis": { + "version": "4.0.0-node10", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.0.0-node10.tgz", + "integrity": "sha512-BRrU0Bo1X9dFGw6KgGz6hWrqQuOlVEDOzkb0QSLZY9sXHqA7pNj7yHPVJRz7y/rj4EOJ3d/D5uxH+ee9leYgsg==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -1701,18 +1693,6 @@ "readable-stream": "^3.4.0" } }, - "node_modules/blessed": { - "version": "0.1.81", - "resolved": "https://registry.npmjs.org/blessed/-/blessed-0.1.81.tgz", - "integrity": "sha512-LoF5gae+hlmfORcG1M5+5XZi4LBmvlXTzwJWzUlPryN/SJdSflZvROM2TwkT0GMpq7oqT48NRd4GS7BiVBc5OQ==", - "license": "MIT", - "bin": { - "blessed": "bin/tput.js" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/bodec": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bodec/-/bodec-0.1.0.tgz", @@ -1821,6 +1801,34 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/charm": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/charm/-/charm-0.1.2.tgz", @@ -1866,34 +1874,6 @@ "node": ">=8.10.0" } }, - "node_modules/cli-tableau/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/cli-tableau/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/color-convert": { "version": "2.0.1", "license": "MIT", @@ -1991,9 +1971,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.18", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", - "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==", + "version": "1.11.15", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.15.tgz", + "integrity": "sha512-MC+DfnSWiM9APs7fpiurHGCoeIx0Gdl6QZBy+5lu8MbYKN5FZEXqOgrundfibdfhGZ15o9hzmZ2xJjZnbvgKXQ==", "license": "MIT" }, "node_modules/debug": { @@ -2148,9 +2128,9 @@ } }, "node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -2158,32 +2138,35 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escape-html": { @@ -2975,15 +2958,6 @@ "license": "ISC", "optional": true }, - "node_modules/lazy": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", - "integrity": "sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==", - "license": "MIT", - "engines": { - "node": ">=0.2.0" - } - }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -3214,25 +3188,6 @@ "node": ">=0.10.0" } }, - "node_modules/nssocket": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/nssocket/-/nssocket-0.6.0.tgz", - "integrity": "sha512-a9GSOIql5IqgWJR3F/JXG4KpJTA3Z53Cj0MeMvGpglytB1nxE4PdFNC0jINe27CS7cGivoynwc054EzCcT3M3w==", - "license": "MIT", - "dependencies": { - "eventemitter2": "~0.4.14", - "lazy": "~1.0.11" - }, - "engines": { - "node": ">= 0.10.x" - } - }, - "node_modules/nssocket/node_modules/eventemitter2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", - "license": "MIT" - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -3414,37 +3369,37 @@ } }, "node_modules/pm2": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/pm2/-/pm2-5.4.3.tgz", - "integrity": "sha512-4/I1htIHzZk1Y67UgOCo4F1cJtas1kSds31N8zN0PybO230id1nigyjGuGFzUnGmUFPmrJ0On22fO1ChFlp7VQ==", + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/pm2/-/pm2-6.0.13.tgz", + "integrity": "sha512-1hS/adMgKoDpX4S1ichJW8SiGpex+oBSZK31dP1FSYOOGtaeuemXzhXPOCefmddgIY4K6v7uu+7xNPnmEnK3ag==", "license": "AGPL-3.0", "dependencies": { - "@pm2/agent": "~2.0.0", - "@pm2/io": "~6.0.1", + "@pm2/agent": "~2.1.1", + "@pm2/blessed": "0.1.81", + "@pm2/io": "~6.1.0", "@pm2/js-api": "~0.8.0", "@pm2/pm2-version-check": "latest", - "async": "~3.2.0", - "blessed": "0.1.81", - "chalk": "3.0.0", - "chokidar": "^3.5.3", - "cli-tableau": "^2.0.0", + "ansis": "4.0.0-node10", + "async": "3.2.6", + "chokidar": "3.6.0", + "cli-tableau": "2.0.1", "commander": "2.15.1", - "croner": "~4.1.92", - "dayjs": "~1.11.5", - "debug": "^4.3.1", + "croner": "4.1.97", + "dayjs": "1.11.15", + "debug": "4.4.3", "enquirer": "2.3.6", "eventemitter2": "5.0.1", "fclone": "1.0.11", - "js-yaml": "~4.1.0", + "js-yaml": "4.1.0", "mkdirp": "1.0.4", "needle": "2.4.0", - "pidusage": "~3.0", + "pidusage": "3.0.2", "pm2-axon": "~4.0.1", "pm2-axon-rpc": "~0.7.1", "pm2-deploy": "~1.0.2", "pm2-multimeter": "^0.1.2", - "promptly": "^2", - "semver": "^7.2", + "promptly": "2.2.0", + "semver": "7.7.2", "source-map-support": "0.5.21", "sprintf-js": "1.1.2", "vizion": "~2.2.1" @@ -3456,7 +3411,7 @@ "pm2-runtime": "bin/pm2-runtime" }, "engines": { - "node": ">=12.0.0" + "node": ">=16.0.0" }, "optionalDependencies": { "pm2-sysmonit": "^1.2.8" @@ -3609,34 +3564,6 @@ "node": ">=8" } }, - "node_modules/pm2/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pm2/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/pm2/node_modules/commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", @@ -3666,6 +3593,18 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/pm2/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prebuild-install": { "version": "7.1.3", "license": "MIT", @@ -3713,15 +3652,15 @@ } }, "node_modules/proxy-agent": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.3.1.tgz", - "integrity": "sha512-Rb5RVBy1iyqOtNl15Cw/llpeLH8bsb37gM1FUfKQ+Wck6xHlbAhWGUFiTRHtkjqGTA5pSHz6+0hrPW/oECihPQ==", + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.2", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.0.1", "proxy-from-env": "^1.1.0", @@ -3912,12 +3851,12 @@ "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -4550,439 +4489,6 @@ "fsevents": "~2.3.3" } }, - "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.11.tgz", - "integrity": "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.11.tgz", - "integrity": "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.11.tgz", - "integrity": "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.11.tgz", - "integrity": "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.11.tgz", - "integrity": "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.11.tgz", - "integrity": "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.11.tgz", - "integrity": "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.11.tgz", - "integrity": "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.11.tgz", - "integrity": "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.11.tgz", - "integrity": "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.11.tgz", - "integrity": "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.11.tgz", - "integrity": "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.11.tgz", - "integrity": "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.11.tgz", - "integrity": "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.11.tgz", - "integrity": "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.11.tgz", - "integrity": "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.11.tgz", - "integrity": "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.11.tgz", - "integrity": "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.11.tgz", - "integrity": "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.11.tgz", - "integrity": "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.11.tgz", - "integrity": "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.11.tgz", - "integrity": "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.11.tgz", - "integrity": "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsx/node_modules/esbuild": { - "version": "0.25.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.11.tgz", - "integrity": "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.11", - "@esbuild/android-arm": "0.25.11", - "@esbuild/android-arm64": "0.25.11", - "@esbuild/android-x64": "0.25.11", - "@esbuild/darwin-arm64": "0.25.11", - "@esbuild/darwin-x64": "0.25.11", - "@esbuild/freebsd-arm64": "0.25.11", - "@esbuild/freebsd-x64": "0.25.11", - "@esbuild/linux-arm": "0.25.11", - "@esbuild/linux-arm64": "0.25.11", - "@esbuild/linux-ia32": "0.25.11", - "@esbuild/linux-loong64": "0.25.11", - "@esbuild/linux-mips64el": "0.25.11", - "@esbuild/linux-ppc64": "0.25.11", - "@esbuild/linux-riscv64": "0.25.11", - "@esbuild/linux-s390x": "0.25.11", - "@esbuild/linux-x64": "0.25.11", - "@esbuild/netbsd-arm64": "0.25.11", - "@esbuild/netbsd-x64": "0.25.11", - "@esbuild/openbsd-arm64": "0.25.11", - "@esbuild/openbsd-x64": "0.25.11", - "@esbuild/openharmony-arm64": "0.25.11", - "@esbuild/sunos-x64": "0.25.11", - "@esbuild/win32-arm64": "0.25.11", - "@esbuild/win32-ia32": "0.25.11", - "@esbuild/win32-x64": "0.25.11" - } - }, "node_modules/tunnel-agent": { "version": "0.6.0", "license": "Apache-2.0", diff --git a/package.json b/package.json index 03cf8d29..da641736 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "4.3.3", + "version": "4.3.4", "description": "Memory compression system for Claude Code - persist context across sessions", "keywords": [ "claude", @@ -39,7 +39,9 @@ "worker:start": "pm2 start ecosystem.config.cjs", "worker:stop": "pm2 stop claude-mem-worker", "worker:restart": "pm2 restart claude-mem-worker", - "worker:logs": "pm2 logs claude-mem-worker" + "worker:logs": "pm2 logs claude-mem-worker", + "usage:analyze": "node scripts/analyze-usage.js", + "usage:today": "node scripts/analyze-usage.js $(date +%Y-%m-%d)" }, "dependencies": { "@anthropic-ai/claude-agent-sdk": "^0.1.27", @@ -48,14 +50,14 @@ "express": "^4.18.2", "glob": "^11.0.3", "handlebars": "^4.7.8", - "pm2": "^5.3.0", + "pm2": "^6.0.13", "zod-to-json-schema": "^3.24.6" }, "devDependencies": { "@types/better-sqlite3": "^7.6.8", "@types/express": "^4.17.21", "@types/node": "^20.0.0", - "esbuild": "^0.20.0", + "esbuild": "^0.25.12", "tsx": "^4.20.6", "typescript": "^5.3.0" } diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json index 62b3104f..1c611b7d 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "claude-mem", - "version": "4.3.3", + "version": "4.3.4", "description": "Persistent memory system for Claude Code - seamlessly preserve context across sessions", "author": { "name": "Alex Newman" diff --git a/plugin/scripts/worker-service.cjs b/plugin/scripts/worker-service.cjs index fe2e0e63..376b4dad 100755 --- a/plugin/scripts/worker-service.cjs +++ b/plugin/scripts/worker-service.cjs @@ -591,8 +591,8 @@ IMPORTANT: This is not the end of the session. You will receive more requests to WHERE up.claude_session_id = ? ORDER BY up.created_at_epoch DESC LIMIT 1 - `).get(c);o.close(),p&&this.chromaSync.syncUserPrompt(p.id,p.sdk_session_id,p.project,p.prompt_text,p.prompt_number,p.created_at_epoch).catch(f=>{Y.failure("WORKER","Failed to sync user_prompt to Chroma",{promptId:p.id},f),process.exit(1)}),u.generatorPromise=this.runSDKAgent(u).catch(f=>{Y.failure("WORKER","SDK agent error",{sessionId:t},f);let d=new Pr;d.markSessionFailed(t),d.close(),this.sessions.delete(t)}),Y.success("WORKER","Session initialized",{sessionId:t,port:this.port}),a.json({status:"initialized",sessionDbId:t,port:this.port})}handleObservation(e,a){let t=parseInt(e.params.sessionDbId,10),{tool_name:s,tool_input:i,tool_output:n,prompt_number:o}=e.body,l=this.sessions.get(t);if(!l){let p=new Pr,f=p.getSessionById(t);p.close(),l={sessionDbId:t,claudeSessionId:f.claude_session_id,sdkSessionId:null,project:f.project,userPrompt:f.user_prompt,pendingMessages:[],abortController:new AbortController,generatorPromise:null,lastPromptNumber:0,observationCounter:0,startTime:Date.now()},this.sessions.set(t,l),l.generatorPromise=this.runSDKAgent(l).catch(d=>{Y.failure("WORKER","SDK agent error",{sessionId:t},d);let v=new Pr;v.markSessionFailed(t),v.close(),this.sessions.delete(t)})}l.observationCounter++;let c=Y.correlationId(t,l.observationCounter),u=Y.formatTool(s,i);Y.dataIn("WORKER",`Observation queued: ${u}`,{correlationId:c,queue:l.pendingMessages.length+1}),l.pendingMessages.push({type:"observation",tool_name:s,tool_input:i,tool_output:n,prompt_number:o}),a.json({status:"queued",queueLength:l.pendingMessages.length})}handleSummarize(e,a){let t=parseInt(e.params.sessionDbId,10),{prompt_number:s}=e.body,i=this.sessions.get(t);if(!i){let n=new Pr,o=n.getSessionById(t);n.close(),i={sessionDbId:t,claudeSessionId:o.claude_session_id,sdkSessionId:null,project:o.project,userPrompt:o.user_prompt,pendingMessages:[],abortController:new AbortController,generatorPromise:null,lastPromptNumber:0,observationCounter:0,startTime:Date.now()},this.sessions.set(t,i),i.generatorPromise=this.runSDKAgent(i).catch(l=>{Y.failure("WORKER","SDK agent error",{sessionId:t},l);let c=new Pr;c.markSessionFailed(t),c.close(),this.sessions.delete(t)})}Y.dataIn("WORKER","Summary requested",{sessionId:t,promptNumber:s,queue:i.pendingMessages.length+1}),i.pendingMessages.push({type:"summarize",prompt_number:s}),a.json({status:"queued",queueLength:i.pendingMessages.length})}handleStatus(e,a){let t=parseInt(e.params.sessionDbId,10),s=this.sessions.get(t);if(!s){a.status(404).json({error:"Session not found"});return}a.json({sessionDbId:t,sdkSessionId:s.sdkSessionId,project:s.project,pendingMessages:s.pendingMessages.length})}async handleDelete(e,a){let t=parseInt(e.params.sessionDbId,10),s=this.sessions.get(t);if(!s){a.status(404).json({error:"Session not found"});return}Y.warn("WORKER","Session delete requested",{sessionId:t}),s.abortController.abort(),s.generatorPromise&&await Promise.race([s.generatorPromise,new Promise(n=>setTimeout(n,5e3))]);let i=new Pr;i.markSessionFailed(t),i.close(),this.sessions.delete(t),Y.info("WORKER","Session deleted",{sessionId:t}),a.json({status:"deleted"})}async runSDKAgent(e){Y.info("SDK","Agent starting",{sessionId:e.sessionDbId});let a=V5();Y.info("SDK",`Using Claude executable: ${a}`,{sessionId:e.sessionDbId});try{let t=Ab({prompt:this.createMessageGenerator(e),options:{model:H5,disallowedTools:B5,abortController:e.abortController,pathToClaudeCodeExecutable:a}});for await(let n of t)if(n.type==="assistant"){let o=n.message.content,l=Array.isArray(o)?o.filter(u=>u.type==="text").map(u=>u.text).join(` -`):typeof o=="string"?o:"",c=l.length;Y.dataOut("SDK",`Response received (${c} chars)`,{sessionId:e.sessionDbId,promptNumber:e.lastPromptNumber}),Y.debug("SDK","Full response",{sessionId:e.sessionDbId},l),this.handleAgentMessage(e,l,e.lastPromptNumber)}let s=Date.now()-e.startTime;Y.success("SDK","Agent completed",{sessionId:e.sessionDbId,duration:`${(s/1e3).toFixed(1)}s`});let i=new Pr;i.markSessionCompleted(e.sessionDbId),i.close(),this.sessions.delete(e.sessionDbId)}catch(t){throw t.name==="AbortError"?Y.warn("SDK","Agent aborted",{sessionId:e.sessionDbId}):Y.failure("SDK","Agent error",{sessionId:e.sessionDbId},t),t}}async*createMessageGenerator(e){let a=cw(e.project,e.claudeSessionId,e.userPrompt);for(Y.dataIn("SDK",`Init prompt sent (${a.length} chars)`,{sessionId:e.sessionDbId,claudeSessionId:e.claudeSessionId,project:e.project}),Y.debug("SDK","Full init prompt",{sessionId:e.sessionDbId},a),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:a}};!e.abortController.signal.aborted;){if(e.pendingMessages.length===0){await new Promise(t=>setTimeout(t,100));continue}for(;e.pendingMessages.length>0;){let t=e.pendingMessages.shift();if(t.type==="summarize"){e.lastPromptNumber=t.prompt_number;let s=new Pr,i=s.getSessionById(e.sessionDbId);s.close();let n=uw(i);Y.dataIn("SDK",`Summary prompt sent (${n.length} chars)`,{sessionId:e.sessionDbId,promptNumber:t.prompt_number}),Y.debug("SDK","Full summary prompt",{sessionId:e.sessionDbId},n),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:n}}}else if(t.type==="observation"){e.lastPromptNumber=t.prompt_number;let s=lw({id:0,tool_name:t.tool_name,tool_input:t.tool_input,tool_output:t.tool_output,created_at_epoch:Date.now()}),i=Y.formatTool(t.tool_name,t.tool_input),n=Y.correlationId(e.sessionDbId,e.observationCounter);Y.dataIn("SDK",`Observation prompt: ${i}`,{correlationId:n,promptNumber:t.prompt_number,size:`${s.length} chars`}),Y.debug("SDK","Full observation prompt",{correlationId:n},s),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:s}}}}}}handleAgentMessage(e,a,t){let s=Y.correlationId(e.sessionDbId,e.observationCounter);Y.info("PARSER",`Processing response (${a.length} chars)`,{sessionId:e.sessionDbId,promptNumber:t,preview:a.substring(0,200)});let i=pw(a,s);i.length>0&&Y.info("PARSER",`Parsed ${i.length} observation(s)`,{correlationId:s,promptNumber:t,types:i.map(l=>l.type).join(", ")});let n=new Pr;for(let l of i){let{id:c,createdAtEpoch:u}=n.storeObservation(e.claudeSessionId,e.project,l,t);Y.success("DB","Observation stored",{correlationId:s,type:l.type,title:l.title,id:c}),this.chromaSync.syncObservation(c,e.claudeSessionId,e.project,l,t,u).then(()=>{Y.success("CHROMA","Observation synced",{correlationId:s,observationId:c})}).catch(p=>{Y.error("CHROMA","Observation sync failed - crashing worker",{correlationId:s,observationId:c},p),process.exit(1)})}Y.info("PARSER","Looking for summary tags...",{sessionId:e.sessionDbId});let o=dw(a,e.sessionDbId);if(o){Y.success("PARSER","Summary parsed successfully!",{sessionId:e.sessionDbId,promptNumber:t,hasRequest:!!o.request,hasInvestigated:!!o.investigated,hasLearned:!!o.learned,hasCompleted:!!o.completed,hasNextSteps:!!o.next_steps});let{id:l,createdAtEpoch:c}=n.storeSummary(e.claudeSessionId,e.project,o,t);Y.success("DB","\u{1F4DD} SUMMARY STORED IN DATABASE",{sessionId:e.sessionDbId,promptNumber:t,id:l}),this.chromaSync.syncSummary(l,e.claudeSessionId,e.project,o,t,c).then(()=>{Y.success("CHROMA","Summary synced",{sessionId:e.sessionDbId,summaryId:l})}).catch(u=>{Y.error("CHROMA","Summary sync failed - crashing worker",{sessionId:e.sessionDbId,summaryId:l},u),process.exit(1)})}else Y.warn("PARSER","NO SUMMARY TAGS FOUND in response",{sessionId:e.sessionDbId,promptNumber:t,contentSample:a.substring(0,500)});n.close()}};async function Z5(){await new Hc().start(),process.on("SIGINT",()=>{Y.warn("SYSTEM","Shutting down (SIGINT)"),process.exit(0)}),process.on("SIGTERM",()=>{Y.warn("SYSTEM","Shutting down (SIGTERM)"),process.exit(0)})}Z5().catch(r=>{Y.failure("SYSTEM","Fatal startup error",{},r),process.exit(1)});0&&(module.exports={WorkerService}); + `).get(c);o.close(),p&&this.chromaSync.syncUserPrompt(p.id,p.sdk_session_id,p.project,p.prompt_text,p.prompt_number,p.created_at_epoch).catch(f=>{Y.failure("WORKER","Failed to sync user_prompt to Chroma",{promptId:p.id},f),process.exit(1)}),u.generatorPromise=this.runSDKAgent(u).catch(f=>{Y.failure("WORKER","SDK agent error",{sessionId:t},f);let d=new Pr;d.markSessionFailed(t),d.close(),this.sessions.delete(t)}),Y.success("WORKER","Session initialized",{sessionId:t,port:this.port}),a.json({status:"initialized",sessionDbId:t,port:this.port})}handleObservation(e,a){let t=parseInt(e.params.sessionDbId,10),{tool_name:s,tool_input:i,tool_output:n,prompt_number:o}=e.body,l=this.sessions.get(t);if(!l){let p=new Pr,f=p.getSessionById(t);p.close(),l={sessionDbId:t,claudeSessionId:f.claude_session_id,sdkSessionId:null,project:f.project,userPrompt:f.user_prompt,pendingMessages:[],abortController:new AbortController,generatorPromise:null,lastPromptNumber:0,observationCounter:0,startTime:Date.now()},this.sessions.set(t,l),l.generatorPromise=this.runSDKAgent(l).catch(d=>{Y.failure("WORKER","SDK agent error",{sessionId:t},d);let v=new Pr;v.markSessionFailed(t),v.close(),this.sessions.delete(t)})}l.observationCounter++;let c=Y.correlationId(t,l.observationCounter),u=Y.formatTool(s,i);Y.dataIn("WORKER",`Observation queued: ${u}`,{correlationId:c,queue:l.pendingMessages.length+1}),l.pendingMessages.push({type:"observation",tool_name:s,tool_input:i,tool_output:n,prompt_number:o}),a.json({status:"queued",queueLength:l.pendingMessages.length})}handleSummarize(e,a){let t=parseInt(e.params.sessionDbId,10),{prompt_number:s}=e.body,i=this.sessions.get(t);if(!i){let n=new Pr,o=n.getSessionById(t);n.close(),i={sessionDbId:t,claudeSessionId:o.claude_session_id,sdkSessionId:null,project:o.project,userPrompt:o.user_prompt,pendingMessages:[],abortController:new AbortController,generatorPromise:null,lastPromptNumber:0,observationCounter:0,startTime:Date.now()},this.sessions.set(t,i),i.generatorPromise=this.runSDKAgent(i).catch(l=>{Y.failure("WORKER","SDK agent error",{sessionId:t},l);let c=new Pr;c.markSessionFailed(t),c.close(),this.sessions.delete(t)})}Y.dataIn("WORKER","Summary requested",{sessionId:t,promptNumber:s,queue:i.pendingMessages.length+1}),i.pendingMessages.push({type:"summarize",prompt_number:s}),a.json({status:"queued",queueLength:i.pendingMessages.length})}handleStatus(e,a){let t=parseInt(e.params.sessionDbId,10),s=this.sessions.get(t);if(!s){a.status(404).json({error:"Session not found"});return}a.json({sessionDbId:t,sdkSessionId:s.sdkSessionId,project:s.project,pendingMessages:s.pendingMessages.length})}async handleDelete(e,a){let t=parseInt(e.params.sessionDbId,10),s=this.sessions.get(t);if(!s){a.status(404).json({error:"Session not found"});return}Y.warn("WORKER","Session delete requested",{sessionId:t}),s.abortController.abort(),s.generatorPromise&&await Promise.race([s.generatorPromise,new Promise(n=>setTimeout(n,5e3))]);let i=new Pr;i.markSessionFailed(t),i.close(),this.sessions.delete(t),Y.info("WORKER","Session deleted",{sessionId:t}),a.json({status:"deleted"})}async runSDKAgent(e){Y.info("SDK","Agent starting",{sessionId:e.sessionDbId});let a=V5();Y.info("SDK",`Using Claude executable: ${a}`,{sessionId:e.sessionDbId});try{let t=Ab({prompt:this.createMessageGenerator(e),options:{model:H5,disallowedTools:B5,abortController:e.abortController,pathToClaudeCodeExecutable:a}});for await(let n of t){if(n.type==="assistant"){let o=n.message.content,l=Array.isArray(o)?o.filter(u=>u.type==="text").map(u=>u.text).join(` +`):typeof o=="string"?o:"",c=l.length;Y.dataOut("SDK",`Response received (${c} chars)`,{sessionId:e.sessionDbId,promptNumber:e.lastPromptNumber}),Y.debug("SDK","Full response",{sessionId:e.sessionDbId},l),this.handleAgentMessage(e,l,e.lastPromptNumber)}n.type==="result"&&n.subtype}let s=Date.now()-e.startTime;Y.success("SDK","Agent completed",{sessionId:e.sessionDbId,duration:`${(s/1e3).toFixed(1)}s`});let i=new Pr;i.markSessionCompleted(e.sessionDbId),i.close(),this.sessions.delete(e.sessionDbId)}catch(t){throw t.name==="AbortError"?Y.warn("SDK","Agent aborted",{sessionId:e.sessionDbId}):Y.failure("SDK","Agent error",{sessionId:e.sessionDbId},t),t}}async*createMessageGenerator(e){let a=cw(e.project,e.claudeSessionId,e.userPrompt);for(Y.dataIn("SDK",`Init prompt sent (${a.length} chars)`,{sessionId:e.sessionDbId,claudeSessionId:e.claudeSessionId,project:e.project}),Y.debug("SDK","Full init prompt",{sessionId:e.sessionDbId},a),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:a}};!e.abortController.signal.aborted;){if(e.pendingMessages.length===0){await new Promise(t=>setTimeout(t,100));continue}for(;e.pendingMessages.length>0;){let t=e.pendingMessages.shift();if(t.type==="summarize"){e.lastPromptNumber=t.prompt_number;let s=new Pr,i=s.getSessionById(e.sessionDbId);s.close();let n=uw(i);Y.dataIn("SDK",`Summary prompt sent (${n.length} chars)`,{sessionId:e.sessionDbId,promptNumber:t.prompt_number}),Y.debug("SDK","Full summary prompt",{sessionId:e.sessionDbId},n),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:n}}}else if(t.type==="observation"){e.lastPromptNumber=t.prompt_number;let s=lw({id:0,tool_name:t.tool_name,tool_input:t.tool_input,tool_output:t.tool_output,created_at_epoch:Date.now()}),i=Y.formatTool(t.tool_name,t.tool_input),n=Y.correlationId(e.sessionDbId,e.observationCounter);Y.dataIn("SDK",`Observation prompt: ${i}`,{correlationId:n,promptNumber:t.prompt_number,size:`${s.length} chars`}),Y.debug("SDK","Full observation prompt",{correlationId:n},s),yield{type:"user",session_id:e.claudeSessionId,parent_tool_use_id:null,message:{role:"user",content:s}}}}}}handleAgentMessage(e,a,t){let s=Y.correlationId(e.sessionDbId,e.observationCounter);Y.info("PARSER",`Processing response (${a.length} chars)`,{sessionId:e.sessionDbId,promptNumber:t,preview:a.substring(0,200)});let i=pw(a,s);i.length>0&&Y.info("PARSER",`Parsed ${i.length} observation(s)`,{correlationId:s,promptNumber:t,types:i.map(l=>l.type).join(", ")});let n=new Pr;for(let l of i){let{id:c,createdAtEpoch:u}=n.storeObservation(e.claudeSessionId,e.project,l,t);Y.success("DB","Observation stored",{correlationId:s,type:l.type,title:l.title,id:c}),this.chromaSync.syncObservation(c,e.claudeSessionId,e.project,l,t,u).then(()=>{Y.success("CHROMA","Observation synced",{correlationId:s,observationId:c})}).catch(p=>{Y.error("CHROMA","Observation sync failed - crashing worker",{correlationId:s,observationId:c},p),process.exit(1)})}Y.info("PARSER","Looking for summary tags...",{sessionId:e.sessionDbId});let o=dw(a,e.sessionDbId);if(o){Y.success("PARSER","Summary parsed successfully!",{sessionId:e.sessionDbId,promptNumber:t,hasRequest:!!o.request,hasInvestigated:!!o.investigated,hasLearned:!!o.learned,hasCompleted:!!o.completed,hasNextSteps:!!o.next_steps});let{id:l,createdAtEpoch:c}=n.storeSummary(e.claudeSessionId,e.project,o,t);Y.success("DB","\u{1F4DD} SUMMARY STORED IN DATABASE",{sessionId:e.sessionDbId,promptNumber:t,id:l}),this.chromaSync.syncSummary(l,e.claudeSessionId,e.project,o,t,c).then(()=>{Y.success("CHROMA","Summary synced",{sessionId:e.sessionDbId,summaryId:l})}).catch(u=>{Y.error("CHROMA","Summary sync failed - crashing worker",{sessionId:e.sessionDbId,summaryId:l},u),process.exit(1)})}else Y.warn("PARSER","NO SUMMARY TAGS FOUND in response",{sessionId:e.sessionDbId,promptNumber:t,contentSample:a.substring(0,500)});n.close()}};async function Z5(){await new Hc().start(),process.on("SIGINT",()=>{Y.warn("SYSTEM","Shutting down (SIGINT)"),process.exit(0)}),process.on("SIGTERM",()=>{Y.warn("SYSTEM","Shutting down (SIGTERM)"),process.exit(0)})}Z5().catch(r=>{Y.failure("SYSTEM","Fatal startup error",{},r),process.exit(1)});0&&(module.exports={WorkerService}); /*! Bundled license information: depd/index.js: diff --git a/scripts/analyze-usage.js b/scripts/analyze-usage.js new file mode 100755 index 00000000..29e9085b --- /dev/null +++ b/scripts/analyze-usage.js @@ -0,0 +1,134 @@ +#!/usr/bin/env node +/** + * Analyze usage logs from ~/.claude-mem/usage-logs/ + * + * Usage: + * node scripts/analyze-usage.js [date] + * + * Example: + * node scripts/analyze-usage.js 2025-11-03 + * node scripts/analyze-usage.js # Uses today's date + */ + +import { readFileSync, readdirSync } from 'fs'; +import { join } from 'path'; +import { homedir } from 'os'; + +const usageDir = join(homedir(), '.claude-mem', 'usage-logs'); + +// Get date from command line or use today +const targetDate = process.argv[2] || new Date().toISOString().split('T')[0]; +const filename = `usage-${targetDate}.jsonl`; +const filepath = join(usageDir, filename); + +console.log(`\n📊 Usage Analysis for ${targetDate}\n`); +console.log(`Reading from: ${filepath}\n`); + +try { + const content = readFileSync(filepath, 'utf-8'); + const lines = content.trim().split('\n'); + + let totalCost = 0; + let totalInputTokens = 0; + let totalOutputTokens = 0; + let totalCacheCreation = 0; + let totalCacheRead = 0; + const projectStats = {}; + const modelStats = {}; + + lines.forEach(line => { + if (!line.trim()) return; + + try { + const entry = JSON.parse(line); + + // Aggregate totals + totalCost += entry.totalCostUsd || 0; + totalInputTokens += entry.usage?.inputTokens || 0; + totalOutputTokens += entry.usage?.outputTokens || 0; + totalCacheCreation += entry.usage?.cacheCreationInputTokens || 0; + totalCacheRead += entry.usage?.cacheReadInputTokens || 0; + + // Project stats + if (!projectStats[entry.project]) { + projectStats[entry.project] = { + cost: 0, + sessions: new Set(), + tokens: 0 + }; + } + projectStats[entry.project].cost += entry.totalCostUsd || 0; + projectStats[entry.project].sessions.add(entry.sessionDbId); + projectStats[entry.project].tokens += (entry.usage?.inputTokens || 0) + (entry.usage?.outputTokens || 0); + + // Model stats + if (!modelStats[entry.model]) { + modelStats[entry.model] = { + cost: 0, + calls: 0, + tokens: 0 + }; + } + modelStats[entry.model].cost += entry.totalCostUsd || 0; + modelStats[entry.model].calls += 1; + modelStats[entry.model].tokens += (entry.usage?.inputTokens || 0) + (entry.usage?.outputTokens || 0); + + } catch (e) { + console.error(`Error parsing line: ${e.message}`); + } + }); + + // Print summary + console.log('═══════════════════════════════════════════════════════════\n'); + console.log(`📈 Total Cost: $${totalCost.toFixed(4)}`); + console.log(`📊 Total API Calls: ${lines.length}`); + console.log(`\n🎯 Token Usage:`); + console.log(` Input Tokens: ${totalInputTokens.toLocaleString()}`); + console.log(` Output Tokens: ${totalOutputTokens.toLocaleString()}`); + console.log(` Cache Creation Tokens: ${totalCacheCreation.toLocaleString()}`); + console.log(` Cache Read Tokens: ${totalCacheRead.toLocaleString()}`); + console.log(` Total Tokens: ${(totalInputTokens + totalOutputTokens).toLocaleString()}`); + + if (totalCacheRead > 0) { + const savings = ((totalCacheRead / (totalInputTokens + totalCacheRead)) * 100).toFixed(1); + console.log(` Cache Hit Rate: ${savings}%`); + } + + console.log(`\n📁 By Project:`); + Object.entries(projectStats) + .sort((a, b) => b[1].cost - a[1].cost) + .forEach(([project, stats]) => { + console.log(` ${project}:`); + console.log(` Cost: $${stats.cost.toFixed(4)}`); + console.log(` Sessions: ${stats.sessions.size}`); + console.log(` Tokens: ${stats.tokens.toLocaleString()}`); + }); + + console.log(`\n🤖 By Model:`); + Object.entries(modelStats) + .sort((a, b) => b[1].cost - a[1].cost) + .forEach(([model, stats]) => { + console.log(` ${model}:`); + console.log(` Cost: $${stats.cost.toFixed(4)}`); + console.log(` Calls: ${stats.calls}`); + console.log(` Tokens: ${stats.tokens.toLocaleString()}`); + console.log(` Avg Cost/Call: $${(stats.cost / stats.calls).toFixed(4)}`); + }); + + console.log('\n═══════════════════════════════════════════════════════════\n'); + +} catch (error) { + if (error.code === 'ENOENT') { + console.error(`❌ No usage log found for ${targetDate}`); + console.log(`\nAvailable logs:`); + try { + const files = readdirSync(usageDir).filter(f => f.endsWith('.jsonl')); + files.forEach(f => console.log(` - ${f}`)); + } catch (e) { + console.error(` Could not read usage logs directory`); + } + } else { + console.error(`❌ Error: ${error.message}`); + } + process.exit(1); +} diff --git a/src/services/worker-service.ts b/src/services/worker-service.ts index 2c2f4ad3..087224bb 100644 --- a/src/services/worker-service.ts +++ b/src/services/worker-service.ts @@ -454,6 +454,11 @@ class WorkerService { // Parse and store with prompt number (non-blocking Chroma sync) this.handleAgentMessage(session, textContent, session.lastPromptNumber); } + + // Capture usage data from result messages + if (message.type === 'result' && message.subtype === 'success') { + // Usage telemetry is captured at SDK level + } } // Mark completed diff --git a/src/utils/usage-logger.ts b/src/utils/usage-logger.ts new file mode 100644 index 00000000..c2f8f579 --- /dev/null +++ b/src/utils/usage-logger.ts @@ -0,0 +1,61 @@ +import { appendFileSync } from 'fs'; +import { join } from 'path'; +import { homedir } from 'os'; + +/** + * Usage data structure from Claude Agent SDK result messages + */ +export interface UsageData { + timestamp: string; + sessionDbId: number; + claudeSessionId: string; + project: string; + promptNumber: number; + model: string; + sessionId: string; // SDK session ID + uuid: string; // SDK message UUID + durationMs: number; + durationApiMs: number; + numTurns: number; + totalCostUsd: number; + usage: { + inputTokens: number; + outputTokens: number; + cacheCreationInputTokens: number; + cacheReadInputTokens: number; + }; +} + +/** + * Logger for capturing usage metrics to JSONL files + */ +export class UsageLogger { + private logDir: string; + private logFile: string; + + constructor() { + this.logDir = join(homedir(), '.claude-mem', 'usage-logs'); + // Create a daily log file + const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD + this.logFile = join(this.logDir, `usage-${date}.jsonl`); + } + + /** + * Log usage data from SDK result message + */ + logUsage(data: UsageData): void { + try { + const line = JSON.stringify(data) + '\n'; + appendFileSync(this.logFile, line, 'utf-8'); + } catch (error) { + console.error('Failed to log usage data:', error); + } + } + + /** + * Get the current log file path + */ + getLogFilePath(): string { + return this.logFile; + } +}