From 2274b5acadf44a2f27e9f1fed6787f1dbe73a3d6 Mon Sep 17 00:00:00 2001 From: Kartik Date: Wed, 10 Jun 2026 01:04:09 +0530 Subject: [PATCH] feat: add @mem0/pi-agent-plugin for Pi Agent memory (#5459) --- docs/docs.json | 6 +- docs/integrations/pi-agent.mdx | 181 + docs/llms.txt | 1 + pi-agent-plugin/CHANGELOG.md | 47 + pi-agent-plugin/LICENSE | 201 + pi-agent-plugin/README.md | 144 + pi-agent-plugin/package.json | 68 + pi-agent-plugin/pnpm-lock.yaml | 4923 +++++++++++++++++ .../skills/context-loader/SKILL.md | 47 + pi-agent-plugin/skills/dream/SKILL.md | 125 + pi-agent-plugin/skills/forget/SKILL.md | 53 + pi-agent-plugin/skills/pin/SKILL.md | 48 + pi-agent-plugin/skills/remember/SKILL.md | 50 + pi-agent-plugin/skills/search/SKILL.md | 41 + pi-agent-plugin/skills/status/SKILL.md | 89 + pi-agent-plugin/skills/tour/SKILL.md | 88 + pi-agent-plugin/src/capture/index.ts | 70 + pi-agent-plugin/src/commands.test.ts | 297 + pi-agent-plugin/src/commands.ts | 291 + pi-agent-plugin/src/config/index.ts | 58 + pi-agent-plugin/src/dream/index.ts | 115 + pi-agent-plugin/src/dream/prompt.ts | 22 + pi-agent-plugin/src/entry.test.ts | 34 + pi-agent-plugin/src/entry.ts | 146 + pi-agent-plugin/src/index.ts | 34 + pi-agent-plugin/src/memory/formatting.ts | 43 + pi-agent-plugin/src/memory/scoping.test.ts | 85 + pi-agent-plugin/src/memory/scoping.ts | 51 + pi-agent-plugin/src/memory/tools.ts | 195 + pi-agent-plugin/src/prompt.ts | 16 + pi-agent-plugin/src/telemetry.ts | 240 + pi-agent-plugin/src/types.ts | 52 + pi-agent-plugin/tests/capture.test.ts | 62 + pi-agent-plugin/tests/config.test.ts | 59 + pi-agent-plugin/tests/dream.test.ts | 59 + pi-agent-plugin/tests/formatting.test.ts | 47 + pi-agent-plugin/tests/scoping.test.ts | 47 + pi-agent-plugin/tests/telemetry.test.ts | 122 + pi-agent-plugin/tests/tools.test.ts | 61 + pi-agent-plugin/tsconfig.json | 24 + pi-agent-plugin/tsup.config.ts | 17 + pi-agent-plugin/vitest.config.ts | 7 + 42 files changed, 8364 insertions(+), 2 deletions(-) create mode 100644 docs/integrations/pi-agent.mdx create mode 100644 pi-agent-plugin/CHANGELOG.md create mode 100644 pi-agent-plugin/LICENSE create mode 100644 pi-agent-plugin/README.md create mode 100644 pi-agent-plugin/package.json create mode 100644 pi-agent-plugin/pnpm-lock.yaml create mode 100644 pi-agent-plugin/skills/context-loader/SKILL.md create mode 100644 pi-agent-plugin/skills/dream/SKILL.md create mode 100644 pi-agent-plugin/skills/forget/SKILL.md create mode 100644 pi-agent-plugin/skills/pin/SKILL.md create mode 100644 pi-agent-plugin/skills/remember/SKILL.md create mode 100644 pi-agent-plugin/skills/search/SKILL.md create mode 100644 pi-agent-plugin/skills/status/SKILL.md create mode 100644 pi-agent-plugin/skills/tour/SKILL.md create mode 100644 pi-agent-plugin/src/capture/index.ts create mode 100644 pi-agent-plugin/src/commands.test.ts create mode 100644 pi-agent-plugin/src/commands.ts create mode 100644 pi-agent-plugin/src/config/index.ts create mode 100644 pi-agent-plugin/src/dream/index.ts create mode 100644 pi-agent-plugin/src/dream/prompt.ts create mode 100644 pi-agent-plugin/src/entry.test.ts create mode 100644 pi-agent-plugin/src/entry.ts create mode 100644 pi-agent-plugin/src/index.ts create mode 100644 pi-agent-plugin/src/memory/formatting.ts create mode 100644 pi-agent-plugin/src/memory/scoping.test.ts create mode 100644 pi-agent-plugin/src/memory/scoping.ts create mode 100644 pi-agent-plugin/src/memory/tools.ts create mode 100644 pi-agent-plugin/src/prompt.ts create mode 100644 pi-agent-plugin/src/telemetry.ts create mode 100644 pi-agent-plugin/src/types.ts create mode 100644 pi-agent-plugin/tests/capture.test.ts create mode 100644 pi-agent-plugin/tests/config.test.ts create mode 100644 pi-agent-plugin/tests/dream.test.ts create mode 100644 pi-agent-plugin/tests/formatting.test.ts create mode 100644 pi-agent-plugin/tests/scoping.test.ts create mode 100644 pi-agent-plugin/tests/telemetry.test.ts create mode 100644 pi-agent-plugin/tests/tools.test.ts create mode 100644 pi-agent-plugin/tsconfig.json create mode 100644 pi-agent-plugin/tsup.config.ts create mode 100644 pi-agent-plugin/vitest.config.ts diff --git a/docs/docs.json b/docs/docs.json index dcb0eb7c7..a75dd1ebe 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -143,7 +143,8 @@ "icon": "robot", "pages": [ "integrations/openclaw", - "integrations/hermes" + "integrations/hermes", + "integrations/pi-agent" ] } ] @@ -464,7 +465,8 @@ "icon": "robot", "pages": [ "integrations/openclaw", - "integrations/hermes" + "integrations/hermes", + "integrations/pi-agent" ] } ] diff --git a/docs/integrations/pi-agent.mdx b/docs/integrations/pi-agent.mdx new file mode 100644 index 000000000..82e7a2d0b --- /dev/null +++ b/docs/integrations/pi-agent.mdx @@ -0,0 +1,181 @@ +--- +title: Pi Agent +description: "Add persistent memory to Pi Agent with the Mem0 plugin semantic search, auto-capture, and dream consolidation." +--- + +Add persistent memory to [**Pi Agent**](https://pi.dev) with `@mem0/pi-agent-plugin`. Your agent forgets everything between sessions — this plugin fixes that by automatically capturing knowledge from conversations, storing it in Mem0's cloud memory layer, and retrieving relevant context before every response. + +## Overview + +The plugin provides: +1. **Auto-capture** — Extracts durable facts from both user and assistant messages automatically +2. **Semantic recall** — Retrieves relevant memories via the `mem0_memory` tool before each response +3. **Dream consolidation** — Periodic maintenance: merges duplicates, resolves contradictions, prunes stale entries +4. **Monorepo-aware scoping** — Uses git root for project detection, consistent across subdirectories +5. **Confirmation dialogs** — Destructive commands ask before acting via Pi's built-in UI +6. **8 skills + 8 commands** — Essential memory management from slash commands and agent-guided workflows + +## Prerequisites + +1. A Mem0 Platform account and API key: + - Sign up at app.mem0.ai + - Get your API key (starts with `m0-`) + +2. Pi Agent installed ([pi.dev](https://pi.dev)) + +3. Your API key added to your shell profile: + + +```bash zsh +echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.zshrc +source ~/.zshrc +``` + +```bash bash +echo 'export MEM0_API_KEY="m0-your-api-key"' >> ~/.bashrc +source ~/.bashrc +``` + + +## Installation + +```bash +pi install npm:@mem0/pi-agent-plugin +``` + +That's it. The extension loads automatically on every Pi session. No config files needed — `MEM0_API_KEY` from your environment is picked up automatically. + + + Start a new Pi session and run `/mem0-status` to verify the connection. You should see your user ID, detected project, and memory count. + + +### Optional Configuration + +For advanced settings, create `~/.pi/agent/mem0-config.json`: + +```json +{ + "apiKey": "m0-your-key-here", + "userId": "your-username", + "autoCapture": true, + "defaultScope": "project", + "dream": { + "enabled": true, + "auto": true, + "minHours": 24, + "minSessions": 5, + "minMemories": 20 + } +} +``` + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| `apiKey` | `string` | `$MEM0_API_KEY` | Mem0 API key. Environment variable takes precedence. | +| `userId` | `string` | `$MEM0_USER_ID` or `"default"` | User identity for memory scoping | +| `autoCapture` | `boolean` | `true` | Store facts from conversations automatically | +| `defaultScope` | `string` | `"project"` | Default memory scope: `project`, `session`, or `global` | +| `dream.enabled` | `boolean` | `true` | Enable dream consolidation | +| `dream.auto` | `boolean` | `true` | Auto-trigger dreams when thresholds are met | +| `dream.minHours` | `number` | `24` | Minimum hours between auto-dreams | +| `dream.minSessions` | `number` | `5` | Minimum sessions before first auto-dream | +| `dream.minMemories` | `number` | `20` | Minimum memories before auto-dream triggers | + +## What's Included + +| Component | Description | +|-----------|-------------| +| `mem0_memory` tool | Agent-callable tool for search, add, get_all, delete, delete_all | +| 8 slash commands | Essential memory management from the command line | +| 8 skills | Guide the agent on how to use each capability | +| Auto-capture | Extracts and stores facts on every `agent_end` event | +| System prompt | Appends memory policy to every agent turn | +| Dream consolidation | Automated memory maintenance with session/time/count gates | + +## Agent Tool + +The `mem0_memory` tool is registered with Pi and callable by the agent during conversations: + +| Action | Required Params | Description | +|--------|----------------|-------------| +| `search` | `query` | Semantic search across memories | +| `add` | `content` | Store a new memory | +| `get_all` | — | List all memories in scope | +| `delete` | `memory_id` | Delete a specific memory | +| `delete_all` | — | Delete all memories in scope | + +All actions accept an optional `scope` parameter: `project` (default), `session`, or `global`. + +Tool output is truncated to 200 lines / 50KB to prevent context overflow. + +## Commands + +| Command | Description | +|---------|-------------| +| `/mem0-remember ` | Store a memory verbatim (no inference) | +| `/mem0-forget ` | Search and delete memories (with confirmation dialog) | +| `/mem0-search ` | Semantic search across memories | +| `/mem0-tour [scope]` | Browse all memories grouped by category | +| `/mem0-dream` | Consolidate — merge duplicates, prune stale, resolve contradictions | +| `/mem0-pin ` | Pin a memory to protect from dream pruning (preserves memory ID) | +| `/mem0-scope ` | Change default scope for this session (project, session, global) | +| `/mem0-status` | Connection health, identity, and memory count | + +## Memory Scopes + +Memories are scoped using Mem0's `user_id`, `app_id`, and `run_id` parameters: + +| Scope | Filters | Use Case | +|-------|---------|----------| +| `project` | user_id + app_id (git root) | **Default.** Project-specific knowledge — decisions, architecture, config | +| `session` | user_id + app_id + run_id | Ephemeral context for the current session only | +| `global` | user_id only | All memories across all your projects | + +The `app_id` is auto-detected from the git repository root (`git rev-parse --show-toplevel`), so all subdirectories within a monorepo share the same memory pool. Falls back to the working directory name for non-git directories. The `run_id` is derived from Pi's session file path. + +## Dream Consolidation + +### Confirmation Dialogs + +Destructive and mutating commands use Pi's built-in `ctx.ui.confirm()` dialog before acting: + +- `/mem0-forget` asks "Delete this memory?" before deleting a single match +- `/mem0-pin` asks "Pin this memory?" before modifying it +- Cancelling either operation is always safe — no changes are made + +### Pin + +`/mem0-pin` uses Mem0's `update()` API to prepend `[PINNED]` to the memory text. This preserves the original memory ID — no add+delete cycle that would lose history or change the UUID. + +### Dream Consolidation + +The plugin includes automated memory maintenance ("dream") that merges duplicates, resolves contradictions, and prunes stale entries. When enabled, dreams auto-trigger after enough sessions, time, and memories accumulate (configurable via `dream.*` settings). Run `/mem0-dream` to trigger consolidation manually at any time. Pinned memories (via `/mem0-pin`) are protected from pruning. + +## Example Workflow + +```text +# Session 1 +You: I prefer dark mode and concise answers. +# Mem0 auto-captures preferences + +# Session 2 (days later) +You: What do you know about my preferences? +# Pi retrieves stored memories — no re-explaining needed +``` + +## Troubleshooting + +- **"No API key found"** — Verify `MEM0_API_KEY` is set: `echo $MEM0_API_KEY`. If empty, add it to your shell profile (see Prerequisites) +- **Extension not loading** — Check Pi startup output for errors. Run `pi -e ./src/entry.ts` from the plugin directory for verbose output +- **Memories not capturing** — Verify `autoCapture` is `true` (default). Check `/mem0-status` for connection health +- **Wrong project detected** — The plugin uses the git repository root as `app_id`. If not in a git repo, it falls back to the working directory name. Run `/mem0-status` to see the detected project +- **Dream not triggering** — All three gates must pass (time, sessions, memories). Use `/mem0-dream` to force it manually + + + + Add Mem0 memory to Claude Code + + + Add Mem0 memory to OpenClaw agents + + diff --git a/docs/llms.txt b/docs/llms.txt index 5ba5fe5fb..eb73d796c 100644 --- a/docs/llms.txt +++ b/docs/llms.txt @@ -259,6 +259,7 @@ If the user is on a pre-current major (Python < 2, TS < 3, or Platform `output_f - [Camel AI](https://docs.mem0.ai/integrations/camel-ai) [Both]: Use when the user is on Camel AI. - [ChatDev](https://docs.mem0.ai/integrations/chatdev) [Both]: Use when the user is on ChatDev. - [Hermes](https://docs.mem0.ai/integrations/hermes) [Both]: Use when the user is on Hermes. +- [Pi Agent](https://docs.mem0.ai/integrations/pi-agent) [Platform]: Use when adding persistent memory to Pi Agent with the Mem0 plugin. - [OpenAI Agents SDK](https://docs.mem0.ai/integrations/openai-agents-sdk) [Both]: Use when the user is on the OpenAI Agents SDK. - [Google AI ADK](https://docs.mem0.ai/integrations/google-ai-adk) [Both]: Use when the user is on Google's Agent Development Kit. - [Mastra](https://docs.mem0.ai/integrations/mastra) [Both]: Use when the user is on Mastra (TypeScript). diff --git a/pi-agent-plugin/CHANGELOG.md b/pi-agent-plugin/CHANGELOG.md new file mode 100644 index 000000000..f4c8ed877 --- /dev/null +++ b/pi-agent-plugin/CHANGELOG.md @@ -0,0 +1,47 @@ +# Changelog + +## 0.1.0 (2026-06-09) + +Initial release of `@mem0/pi-agent-plugin` — persistent semantic memory for Pi Agent. + +### Features + +- **Extension entry point** — registers `mem0_memory` tool, 8 slash commands, and auto-capture hooks +- **Agent tool** (`mem0_memory`) — search, add, get_all, delete, delete_all with scoped filters +- **Auto-capture** — extracts and stores memories from both user and assistant messages on `agent_end` +- **Dream consolidation** — automated memory maintenance: merge duplicates, resolve contradictions, prune stale entries. Gated by session count, time elapsed, and memory count thresholds +- **System prompt injection** — appends `MEMORY_POLICY` to every agent turn via `before_agent_start` +- **Monorepo-aware project scoping** — uses `git rev-parse --show-toplevel` for consistent app_id across subdirectories +- **3 memory scopes** — project (default), session, global +- **10 memory categories** — identity, preferences, goals, projects, decisions, technical, relationships, routines, lessons, work +- **8 skills** — context-loader, remember, search, forget, dream, tour, pin, status +- **Confirmation dialogs** — `/mem0-forget` and `/mem0-pin` ask for confirmation before destructive or mutating actions via `ctx.ui.confirm()` +- **Pin preserves memory ID** — `/mem0-pin` uses `mem0.update()` instead of add+delete, keeping the original UUID +- **Full memory IDs** — all displayed memory references show the complete UUID, not truncated short IDs +- **Dream gate optimization** — `dreamChecked` flag prevents repeated `getAll` API calls when the memory gate fails +- **Output truncation** — tool results capped at 200 lines / 50KB per Pi docs +- **Signal cancellation** — all tool actions respect `AbortSignal` +- **Session shutdown cleanup** — releases dream lock on `session_shutdown` +- **PostHog telemetry** — batched event queue with PII-safe error payloads + +### Commands + +| Command | Description | +|---------|-------------| +| `/mem0-remember` | Store a memory verbatim (no inference) | +| `/mem0-forget` | Search and delete memories (with confirmation) | +| `/mem0-search` | Semantic search across memories | +| `/mem0-tour` | Browse all memories by category | +| `/mem0-dream` | Trigger memory consolidation | +| `/mem0-pin` | Pin a memory to protect from pruning (preserves ID) | +| `/mem0-scope` | Change default scope for this session | +| `/mem0-status` | Connection health and diagnostics | + +### Hooks + +| Hook | Purpose | +|------|---------| +| `session_start` | Detect project (git root), resolve session ID, increment dream counter | +| `before_agent_start` | Inject memory policy into system prompt, auto-trigger dream if gates pass | +| `agent_end` | Auto-capture conversation memories, check dream completion | +| `session_shutdown` | Release dream lock, flush telemetry | diff --git a/pi-agent-plugin/LICENSE b/pi-agent-plugin/LICENSE new file mode 100644 index 000000000..bfa36bdd4 --- /dev/null +++ b/pi-agent-plugin/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [2026] [Taranjeet Singh] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/pi-agent-plugin/README.md b/pi-agent-plugin/README.md new file mode 100644 index 000000000..a819c464f --- /dev/null +++ b/pi-agent-plugin/README.md @@ -0,0 +1,144 @@ +# @mem0/pi-agent-plugin + +Persistent semantic memory for [Pi Agent](https://pi.dev), powered by [Mem0](https://mem0.ai). + +This extension gives Pi Agent long-term memory that persists across sessions, projects, and devices. Memories are automatically captured from conversations and can be searched, managed, and consolidated through slash commands and an agent-accessible tool. + +## Features + +- **Automatic memory capture** — learns from every conversation (both user and assistant messages) +- **Semantic search** — find memories by meaning, not just keywords +- **Scoped memory** — project, session, or global scope +- **Monorepo-aware** — uses git root for project detection, consistent app_id across subdirectories +- **Dream consolidation** — merges duplicates, resolves contradictions, prunes stale entries +- **Confirmation dialogs** — destructive commands ask before acting +- **8 slash commands** — essential memory management from the command line +- **Agent tool** — `mem0_memory` tool lets the agent search and store memories autonomously + +## Setup + +### 1. Get an API key + +Sign up at [app.mem0.ai](https://app.mem0.ai/dashboard/api-keys) and copy your API key. + +### 2. Install + +```bash +pi install npm:@mem0/pi-agent-plugin +``` + +### 3. Configure + +Set the API key as an environment variable: + +```bash +export MEM0_API_KEY="m0-your-key-here" +``` + +Or create a config file at `~/.pi/agent/mem0-config.json`: + +```json +{ + "apiKey": "m0-your-key-here", + "userId": "your-username", + "autoCapture": true, + "defaultScope": "project", + "dream": { + "enabled": true, + "auto": true, + "minHours": 24, + "minSessions": 5, + "minMemories": 20 + } +} +``` + +Environment variables (`MEM0_API_KEY`, `MEM0_USER_ID`) override the config file. + +## Commands + +| Command | Description | +|---------|-------------| +| `/mem0-remember ` | Store a memory verbatim (no inference) | +| `/mem0-forget ` | Search and delete memories (with confirmation) | +| `/mem0-search ` | Semantic search across memories | +| `/mem0-tour [scope]` | Browse all memories grouped by category | +| `/mem0-dream` | Consolidate — merge duplicates, prune stale, resolve contradictions | +| `/mem0-pin ` | Pin a memory to protect from dream pruning (preserves ID) | +| `/mem0-scope ` | Change default scope for this session | +| `/mem0-status` | Connection health, identity, and memory count | + +## Skills + +The plugin includes 8 skills that guide the agent on how to use each capability: + +| Skill | Purpose | +|-------|---------| +| `context-loader` | Pre-fetch relevant memories at session start | +| `remember` | Store facts with category classification | +| `search` | Quick semantic search with compact results | +| `forget` | Delete memories with confirmation | +| `dream` | Memory consolidation workflow | +| `tour` | Full memory walkthrough by category | +| `pin` | Protect critical memories from pruning | +| `status` | Health check and diagnostics | + +## Memory Scopes + +| Scope | Filters | Use case | +|-------|---------|----------| +| `project` | user + app_id (git root) | Default. Project-specific knowledge | +| `session` | user + app_id + run_id | Ephemeral, session-only context | +| `global` | user only | All memories across all your projects | + +Project scoping uses `git rev-parse --show-toplevel` to detect the repository root, so all subdirectories within a monorepo share the same memory pool. + +## Memory Categories + +Memories are automatically classified into 10 general-purpose categories: + +| Category | Description | +|----------|-------------| +| `identity` | Personal details, background, self-descriptions | +| `preferences` | Likes, dislikes, habits, preferred approaches | +| `goals` | Objectives, aspirations, targets | +| `projects` | Ongoing work, initiatives, areas of focus | +| `decisions` | Choices made, rationale, trade-offs | +| `technical` | Technical knowledge, tools, configurations | +| `relationships` | People, teams, organizations | +| `routines` | Recurring patterns, workflows, schedules | +| `lessons` | Insights learned, mistakes to avoid | +| `work` | Professional context, role, responsibilities | + +## Architecture + +``` +pi-agent-plugin/ +├── src/ +│ ├── entry.ts # Extension entry point +│ ├── index.ts # Barrel exports +│ ├── commands.ts # 8 slash commands +│ ├── prompt.ts # System prompt injection (MEMORY_POLICY) +│ ├── types.ts # Shared interfaces and categories +│ ├── telemetry.ts # PostHog telemetry (batched, PII-safe) +│ ├── config/ # Config loading (~/.pi/agent/mem0-config.json) +│ ├── memory/ # Tool registration, scoping (git root), formatting +│ ├── capture/ # Auto-capture from conversations (user + assistant) +│ └── dream/ # Consolidation state, gating, locking, prompts +├── skills/ # 8 SKILL.md files for Pi Agent +├── tests/ # Vitest unit tests +└── dist/ # Built output (ESM + DTS) +``` + +## Development + +```bash +pnpm install # Install dependencies +pnpm run typecheck # Type check +pnpm run test # Run tests +pnpm run build # Build (ESM + declarations) +``` + +## License + +[Apache-2.0](LICENSE) diff --git a/pi-agent-plugin/package.json b/pi-agent-plugin/package.json new file mode 100644 index 000000000..1716eceb6 --- /dev/null +++ b/pi-agent-plugin/package.json @@ -0,0 +1,68 @@ +{ + "name": "@mem0/pi-agent-plugin", + "version": "0.1.0", + "type": "module", + "description": "Mem0 memory extension for Pi Agent persistent, scoped, semantic memory across sessions and projects", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/mem0ai/mem0/pi-agent-plugin", + "directory": "pi-agent-plugin" + }, + "keywords": [ + "pi-package", + "pi-extension", + "skills", + "memory", + "mem0", + "semantic-memory", + "persistent-memory", + "agent-memory" + ], + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + } + }, + "publishConfig": { + "access": "public" + }, + "files": [ + "dist", + "src", + "skills", + "CHANGELOG.md", + "README.md", + "LICENSE" + ], + "pi": { + "extensions": ["./src/entry.ts"], + "skills": ["./skills"] + }, + "scripts": { + "build": "tsup", + "test": "vitest run", + "test:watch": "vitest", + "typecheck": "tsc --noEmit" + }, + "peerDependencies": { + "@earendil-works/pi-coding-agent": "*", + "@earendil-works/pi-ai": "*", + "typebox": "*" + }, + "devDependencies": { + "@earendil-works/pi-ai": "^0.79.0", + "@earendil-works/pi-coding-agent": "^0.79.0", + "@types/node": "^25.9.2", + "tsup": "^8.5.0", + "typebox": "^1.2.3", + "typescript": "^6.0.3", + "vitest": "^4.1.7" + }, + "dependencies": { + "mem0ai": "^3.0.6" + } +} diff --git a/pi-agent-plugin/pnpm-lock.yaml b/pi-agent-plugin/pnpm-lock.yaml new file mode 100644 index 000000000..32b106961 --- /dev/null +++ b/pi-agent-plugin/pnpm-lock.yaml @@ -0,0 +1,4923 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + mem0ai: + specifier: ^3.0.6 + version: 3.0.6(@anthropic-ai/sdk@0.91.1(zod@3.25.76))(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260609.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@2.2.1)(@qdrant/js-client-rest@1.18.0(typescript@6.0.3))(@supabase/supabase-js@2.108.0)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.21.0)(redis@5.12.1)(ws@8.21.0) + devDependencies: + '@earendil-works/pi-ai': + specifier: ^0.79.0 + version: 0.79.0(ws@8.21.0)(zod@3.25.76) + '@earendil-works/pi-coding-agent': + specifier: ^0.79.0 + version: 0.79.0(ws@8.21.0)(zod@3.25.76) + '@types/node': + specifier: ^25.9.2 + version: 25.9.2 + tsup: + specifier: ^8.5.0 + version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(typescript@6.0.3)(yaml@2.9.0) + typebox: + specifier: ^1.2.3 + version: 1.2.3 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + vitest: + specifier: ^4.1.7 + version: 4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0)) + +packages: + + '@anthropic-ai/sdk@0.91.1': + resolution: {integrity: sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + resolution: {integrity: sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.974.19': + resolution: {integrity: sha512-SMNfLCU/41xxfFaC5Slwy8V/f1FRhakvyeeMeDeIxqNF0DzhDlXsXnJDELJYke1EtnJbfzfilW7tvulGfxMY6A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.45': + resolution: {integrity: sha512-ZPsnLyrpDRmojKrBbJykASyLLVFkjyD+fWATeSuYgaqablijGOzxPxEKyrwUvNg+bgSQ7PkW2FTu65Xco19Gag==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.47': + resolution: {integrity: sha512-1XdgHDIPbARHuzZXM7ouzIbSUZFU9dTi9k+ryMhiZU4QCam4dvwOyUEFjEHNxAZehCYUIOmsSUZ2un6BIgUkWg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.51': + resolution: {integrity: sha512-f8sRTVyM+9BbzQKPlUP9dVVpgNEu65jFckNAAGzRfCrlaSi5AWUbCKEHIMcIYokv8pWblSKEqHkqKYZtwINnhw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.50': + resolution: {integrity: sha512-NHHsKoMhw6UylSU0XDnDc87+IQW8tRBTIe6vnOX12GSIlBDtoce6bSzONleIglCyu8d3H9bmTSfk+sIN5yh3WA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.53': + resolution: {integrity: sha512-z/JJ8Qvf2GiTn4bw+x8k7wQjxmPpNsiwZ7ls/h1cZHikrSpS0+65lB+lafnXZlxv1lqH4k6rQwh+2UsycC662g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.45': + resolution: {integrity: sha512-QMJXjTGLmHE4Ie03T5H4hHOLfcvMc9DaODO6b5dgte3S8ECf5bBuHUJW4cQREcYZyRkOU8iymqtiBxqF4icxZg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.50': + resolution: {integrity: sha512-pQ9ww4G53gwHlon1NMz25JhaBo13E9Jv+VVgjh39C/yzvby+xhSnEOb+VDYShKNCh1TbttMF/5CFCHkZrIqOcA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.50': + resolution: {integrity: sha512-9DbaPaT2aMbz18wtSpq9HVBErjBQwxykqTFgG6n8Bn05GN68mITz+G1869ekYx0mVT/BDjETj5czz/3cPgLwxA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.21': + resolution: {integrity: sha512-mVC0hOmwGJmNFezZ+wM8Sqfap/LjsMavEf2Evl0YWrLAcrdZOEdjnY8nRvgakVViWJSGm2eJxLuPVHGdeV06kA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.17': + resolution: {integrity: sha512-tdbnXbw73ww62ABWP0G0Z/euvFowEEvAoi/zG4NaZo7HJFpfGho/Z65HyVzkJLT1cMsUregr4pTyxljlarT0wA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.27': + resolution: {integrity: sha512-V/IgUogQm/NSGlNglDCkREirQXgjyrrq64vPt5qcRTGhEJJwPcUB3RyYE6iZ63WNGp4Ezc+JtVRA4QlSbhDvVQ==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.997.18': + resolution: {integrity: sha512-xBWrodBvW5SHCZV11UZUJG0pSHkLCEREIBoNbff1C1sacOUCmxJnTCPE80sCGLCtqgXg98I2MQJe2z28tcZSsw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.33': + resolution: {integrity: sha512-Hn0RThJEbyOZWV2PV9Z4YD3nitGPxybmyU17dSe9b61WOBcKnqS0WTtM3c1zyZq9WnGiyrfi/i+UBPUk7cM8Ug==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1048.0': + resolution: {integrity: sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1064.0': + resolution: {integrity: sha512-sjI+iA4JtgeckBgKwPQF7KzWillRoNDmtpiM0TRa0syiAKFHKUSf84kPXSO3+gA7aMMSxrcxzOM2oPSecaJvEA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.12': + resolution: {integrity: sha512-43ajd1NF0RMgX5k0hxCNUyEdrtFUsb2aHT2QvpktSC/2Eyb2Jr/JPVqdp0XIoaHWikZJq5tNWSLO6kB5q2eMCA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.7': + resolution: {integrity: sha512-M0D6oIpohdNHjc7udzTHEQyot0+0iuA36jc2I9Hps+f/GtKi2HO/pyijQnCnNcwZqLB5+rtn81z3eZK/GyjAmA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.29': + resolution: {integrity: sha512-fk0niuGFxfi8yIJuMVM4mhwObkiQSuwZFj3tAPrLVx64Pk3BkrEIpqjzHKY4hKoEBUD6Jg/S74Zj9jy+5F3DnQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} + engines: {node: '>=18.0.0'} + + '@azure/abort-controller@2.1.2': + resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} + engines: {node: '>=18.0.0'} + + '@azure/core-auth@1.10.1': + resolution: {integrity: sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==} + engines: {node: '>=20.0.0'} + + '@azure/core-client@1.10.2': + resolution: {integrity: sha512-1D2LpsU7y9xrqKjdIbsB7PlrRePw0xsVV8p+AKTlzITrWmscajryfJCdDJB/oGwvDI5HmRo04eMMADB67uwAwQ==} + engines: {node: '>=20.0.0'} + + '@azure/core-http-compat@2.4.0': + resolution: {integrity: sha512-f1P96IB399YiN2ARYHP7EpZi3Bf3wH4SN2lGzrw7JVwm7bbsVYtf2iKSBwTywD2P62NOPZGHFSZi+6jjb75JuA==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@azure/core-client': ^1.10.0 + '@azure/core-rest-pipeline': ^1.22.0 + + '@azure/core-paging@1.6.2': + resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==} + engines: {node: '>=18.0.0'} + + '@azure/core-rest-pipeline@1.24.0': + resolution: {integrity: sha512-PpLsoDQ3AMmKZ0VU+0GrmqMxgp/sExjlVm4R+nLWngeoEGAzOIPVifaxKGU5gMv+nWELUoHfvrolWD+ZS/nFJg==} + engines: {node: '>=20.0.0'} + + '@azure/core-tracing@1.3.1': + resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} + engines: {node: '>=20.0.0'} + + '@azure/core-util@1.13.1': + resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} + engines: {node: '>=20.0.0'} + + '@azure/identity@4.13.1': + resolution: {integrity: sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==} + engines: {node: '>=20.0.0'} + + '@azure/logger@1.3.0': + resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} + engines: {node: '>=20.0.0'} + + '@azure/msal-browser@5.12.0': + resolution: {integrity: sha512-eNf2aqx1C6I0yT1GEu5ukblFrmaBXGfe1bivpmlfqvK7giPZvoXLa404C8EfeHVsy6EIryfQuPRzuW1fPxWlHg==} + engines: {node: '>=0.8.0'} + + '@azure/msal-common@16.7.0': + resolution: {integrity: sha512-Jb8Y7pX6KM42SIT7KWP6YbY3+vLbwB5b5m+tpiiOzMU1QeyelQzs9lO8jv1e7/Uj9r7tg7VjPvW4T0KB1jF3UQ==} + engines: {node: '>=0.8.0'} + + '@azure/msal-node@5.2.3': + resolution: {integrity: sha512-YYX4TchEVddVBiybKvKhV9QO/q22jgewP+BVxKG7Uh115voPcviGlypbKERDsqQdAiSTJrwi80gcWFjYKdo8+Q==} + engines: {node: '>=20'} + + '@azure/search-documents@12.2.0': + resolution: {integrity: sha512-4+Qw+qaGqnkdUCq/vEFzk/bkROogTvdbPb1fmI8poxNfDDN1q2WHxBmhI7CYwesrBj1yXC4i5E0aISBxZqZi0g==} + engines: {node: '>=20.0.0'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@cfworker/json-schema@4.1.1': + resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==} + + '@cloudflare/workers-types@4.20260609.1': + resolution: {integrity: sha512-krGHtwSApCFBjTe1NTx/TFQ0P5i/bHGQOqCPnCLssb8rOKaAG4JkPFJZsossr0z/ZTMnpP2Tid5jWju+/i0hCA==} + + '@earendil-works/pi-agent-core@0.79.0': + resolution: {integrity: sha512-jQOtYjRGZ7+XC/olw9euLd2V03vkAPO8u0sSnQoLbyOQZz66dEBZrklTESk34Sf3AaeBSua28wjZR48ch1aXJQ==} + engines: {node: '>=22.19.0'} + + '@earendil-works/pi-ai@0.79.0': + resolution: {integrity: sha512-D/2aDoe9vcCbqAztALQcKkdqXGuaQcqAzLm8LfUhNaorwoIHkwnaAuDVlo+OkF5clpEwS8Z1bk2o8NiSrwEdsA==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@earendil-works/pi-coding-agent@0.79.0': + resolution: {integrity: sha512-pZoXk65vFR3dAzzmPNWEX61aHnT6+BaVhTyFDQAs1DyumaMeWpvzRV9ZrGxqlbVLwhrq+0LnXbaqDAFkhe2+MQ==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@earendil-works/pi-tui@0.79.0': + resolution: {integrity: sha512-qAQWMruW7YKbk2hPcTD4INtXfvIySXifbPQ+mFY5j3J8yf2tfElkh+gGPuBvgPKPT0z9WiAkd7iySCuQq0txuQ==} + engines: {node: '>=22.19.0'} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@google/genai@1.52.0': + resolution: {integrity: sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@langchain/core@1.1.48': + resolution: {integrity: sha512-fQU6Guyb1pwc2fEplmA8FPbKfOMAofjnyJzExevro0FxEiuGHE18Ov/ZHmT9trWCDTZRI9eW1VIc6aChxV8pAQ==} + engines: {node: '>=20'} + + '@mariozechner/clipboard-darwin-arm64@0.3.9': + resolution: {integrity: sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@mariozechner/clipboard-darwin-universal@0.3.9': + resolution: {integrity: sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ==} + engines: {node: '>= 10'} + os: [darwin] + + '@mariozechner/clipboard-darwin-x64@0.3.9': + resolution: {integrity: sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@mariozechner/clipboard-linux-arm64-gnu@0.3.9': + resolution: {integrity: sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@mariozechner/clipboard-linux-arm64-musl@0.3.9': + resolution: {integrity: sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@mariozechner/clipboard-linux-riscv64-gnu@0.3.9': + resolution: {integrity: sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@mariozechner/clipboard-linux-x64-gnu@0.3.9': + resolution: {integrity: sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@mariozechner/clipboard-linux-x64-musl@0.3.9': + resolution: {integrity: sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@mariozechner/clipboard-win32-arm64-msvc@0.3.9': + resolution: {integrity: sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@mariozechner/clipboard-win32-x64-msvc@0.3.9': + resolution: {integrity: sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@mariozechner/clipboard@0.3.9': + resolution: {integrity: sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA==} + engines: {node: '>= 10'} + + '@mistralai/mistralai@2.2.1': + resolution: {integrity: sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==} + + '@mongodb-js/saslprep@1.4.11': + resolution: {integrity: sha512-o9rAHc0IpIjuPSxRutWpE1F62x7n+4mVS4rCNHkzhIUMQcc18bb6xEq5wd2NdN0WjepIyXIppRshYI2kQDOZVA==} + + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@nodable/entities@2.1.1': + resolution: {integrity: sha512-Pig3HxDIoMgjdEH8OCf/dkcTmLFjJRjWuq8jSnklu284/TKOPibSRERmOykiwmyXTtv61mP+44f3GMx0tLAyjg==} + + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.2': + resolution: {integrity: sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.1': + resolution: {integrity: sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==} + + '@qdrant/js-client-rest@1.18.0': + resolution: {integrity: sha512-/0dqX5uV9chC1DnYSnU4gNMrDqse/pt6hHg3Rqqpl5isH7xl1xSNvffjzBoxycDD79luWn7Ho6Rh/61sOs5DNw==} + engines: {node: '>=18.17.0', pnpm: '>=8'} + peerDependencies: + typescript: '>=4.7' + + '@qdrant/openapi-typescript-fetch@1.2.6': + resolution: {integrity: sha512-oQG/FejNpItrxRHoyctYvT3rwGZOnK4jr3JdppO/c78ktDvkWiPXPHNsrDf33K9sZdRb6PR7gi4noIapu5q4HA==} + engines: {node: '>=18.0.0', pnpm: '>=8'} + + '@redis/bloom@5.12.1': + resolution: {integrity: sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 + + '@redis/client@5.12.1': + resolution: {integrity: sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@node-rs/xxhash': ^1.1.0 + '@opentelemetry/api': '>=1 <2' + peerDependenciesMeta: + '@node-rs/xxhash': + optional: true + '@opentelemetry/api': + optional: true + + '@redis/json@5.12.1': + resolution: {integrity: sha512-eOze75esLve4vfqDel7aMX08CNaiLLQS2fV8mpRN9NxPe1rVR4vQyYiW/OgtGUysF6QOr9ANhfxABKNOJfXdKg==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 + + '@redis/search@5.12.1': + resolution: {integrity: sha512-ItlxbxC9cKI6IU1TLWoczwJCRb6TdmkEpWv05UrPawqaAnWGRu3rcIqsc5vN483T2fSociuyV1UkWIL5I4//2w==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 + + '@redis/time-series@5.12.1': + resolution: {integrity: sha512-c6JL6E3EcZJuNqKFz+KM+l9l5mpcQiKvTwgA3blt5glWJ8hjDk0yeHN3beE/MpqYIQ8UEX44ItQzgkE/gCBELQ==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 + + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@rollup/rollup-android-arm-eabi@4.61.1': + resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.61.1': + resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.61.1': + resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.61.1': + resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.61.1': + resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.61.1': + resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.61.1': + resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.61.1': + resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.61.1': + resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.61.1': + resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.61.1': + resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.61.1': + resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.61.1': + resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.61.1': + resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.61.1': + resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.61.1': + resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.61.1': + resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.61.1': + resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.61.1': + resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.61.1': + resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.61.1': + resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.61.1': + resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.61.1': + resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.61.1': + resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} + cpu: [x64] + os: [win32] + + '@silvia-odwyer/photon-node@0.3.4': + resolution: {integrity: sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==} + + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} + + '@smithy/core@3.24.6': + resolution: {integrity: sha512-wBXDRup6UU97VKyaiRo8AssnfStPtG0oAAfpq/bC0a1YYau8pM86YB4kM6ccoVi1mS8l/UHbn9oDM+7uozr/ug==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.3.8': + resolution: {integrity: sha512-5cAM+KZC02sTqDt6NaLXyu50M/GNMd1eTzDVR8Lb0BBsVtu7RWHo47VPPEEv1vt3Yub6uzr+M5FHC+GtoT0USg==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.4.6': + resolution: {integrity: sha512-FEwEYJ1jlBKdhe9TPzfghEi1bP55ZeEImlDkEa62bBBYzUcnB6RUCyuiS2mqKt6ZVjUbBgcNhzfIctH+Hevx9g==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.7.3': + resolution: {integrity: sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.7.7': + resolution: {integrity: sha512-ZAFvHXrEk6K180EVhmZVg8GU5pUH5BSFqRs27JW3j1qEFx9YyYwWFx17x/MHcjALYimGAji7qEOlF1++be+G5A==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.4.6': + resolution: {integrity: sha512-Ojg4B6oIDlIr1R86xCDJt1zJWnYa0VINmqdjfe9qxWjdRivHalZ3iSlQgVqYbW0MdpFOC5XfHEWsnbmdnpIILQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.14.3': + resolution: {integrity: sha512-YupL0ZWmFtJexUN2cHzkvvF/b9pKrtAIfT1o7/oY/Ppu8IYeZ+lDPM5vZdQJaSeA132dJCqojjGC9NhXeF71VQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@supabase/auth-js@2.108.0': + resolution: {integrity: sha512-0CzVGVqHfNOhRQVEcAmu58Mex2Ce0zL3aGfyV+iFQjTK6OntLK/hLCLr/VDRX0E8/2CdsiY99L7fZ/8ys/op4w==} + engines: {node: '>=20.0.0'} + + '@supabase/functions-js@2.108.0': + resolution: {integrity: sha512-lqEGDzT7QBUuKYzi5lHpV/XecXT9wikzcbXMbFo6krNpSDynD1sHM8wcsfB/BAqa4NkFuy3vF4JCV8MeakV8IQ==} + engines: {node: '>=20.0.0'} + + '@supabase/phoenix@0.4.2': + resolution: {integrity: sha512-YSAGnmDAfuleFCVt3CeurQZAhxRfXWeZIIkwp7NhYzQ1UwW6ePSnzsFAiUm/mbCkfoCf70QQHKW/K6RKh52a4A==} + + '@supabase/postgrest-js@2.108.0': + resolution: {integrity: sha512-8AwTkPqowDYv/qh016CyXeZ3Ukpw6NHyfqc7DWV4afLR2hAiapf3zRKV2ZLG+//T1LK84HrR6X8VBwfgHWmNyw==} + engines: {node: '>=20.0.0'} + + '@supabase/realtime-js@2.108.0': + resolution: {integrity: sha512-N3xR0u7TNr+c5wuLSU60rcfu/H/8N0WBs7iHWwjI/NxKwY3XWSyLUbpbpU8bzmL0dA/Gk9Mupri8mxKUXBW+iw==} + engines: {node: '>=20.0.0'} + + '@supabase/storage-js@2.108.0': + resolution: {integrity: sha512-zMYQmh87CId7d8i/1FIfv4fMDcXPutmIJSpoY58GLXi7M266MNzxWGNabDk4i555Oj1Nqtsu2i3Qo3rpWUXO6A==} + engines: {node: '>=20.0.0'} + + '@supabase/supabase-js@2.108.0': + resolution: {integrity: sha512-AjPoimM9MZLZbddnlDBGmpZ/Tas1dNcJvuZy/VD1AfmrjBC8J2RSw6UOqR4ISLLlEioOLca/5t1crFnAxa0wRQ==} + engines: {node: '>=20.0.0'} + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + + '@types/node@18.19.130': + resolution: {integrity: sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==} + + '@types/node@25.9.2': + resolution: {integrity: sha512-G05zqtJhcDLb8uslf5EjCxXg9G1KQxiV8OS0R26IC//Eoyitzqe8z37I7cqvnZlrlSfgocQRfSn/AHBZJJFyGw==} + + '@types/pg@8.11.0': + resolution: {integrity: sha512-sDAlRiBNthGjNFfvt0k6mtotoVYVQ63pA8R4EMWka7crawSR60waVYR0HAgmPRs/e2YaeJTD/43OoZ3PFw80pw==} + + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/webidl-conversions@7.0.3': + resolution: {integrity: sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==} + + '@types/whatwg-url@13.0.0': + resolution: {integrity: sha512-N8WXpbE6Wgri7KUSvrmQcqrMllKZ9uxkYWMt+mCSGwNc0Hsw9VQTW7ApqI4XNrx6/SaM2QQJCzMPDEXE058s+Q==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + + '@typespec/ts-http-runtime@0.3.6': + resolution: {integrity: sha512-jIXhD0eWQ1JA6ln/5Dltyx22UxWNrw0hZmhy2rlv6m6KgF7kplHx3g0fzi09lNmTJQRR91OlemYp3xFnvDK9og==} + engines: {node: '>=20.0.0'} + + '@vitest/expect@4.1.8': + resolution: {integrity: sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==} + + '@vitest/mocker@4.1.8': + resolution: {integrity: sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.8': + resolution: {integrity: sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==} + + '@vitest/runner@4.1.8': + resolution: {integrity: sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==} + + '@vitest/snapshot@4.1.8': + resolution: {integrity: sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==} + + '@vitest/spy@4.1.8': + resolution: {integrity: sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==} + + '@vitest/utils@4.1.8': + resolution: {integrity: sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + afinn-165-financialmarketnews@3.0.0: + resolution: {integrity: sha512-0g9A1S3ZomFIGDTzZ0t6xmv4AuokBvBmpes8htiyHpH7N4xDmvSQL6UxL/Zcs2ypRb3VwgCscaD8Q3zEawKYhw==} + + afinn-165@2.0.2: + resolution: {integrity: sha512-mJ/RLUfpXfQA6bzugv+bBsc/QYkVrKaLYeS8fWBpKbTCsonv4iuV9ET0fgReEunm9vKLkaNgnekuSNlTC3WQ1Q==} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + apparatus@0.0.10: + resolution: {integrity: sha512-KLy/ugo33KZA7nugtQ7O0E1c8kQ52N3IvD/XgIh4w/Nr28ypfkwDfA67F1ev4N1m5D+BOk1+b2dEJDfpj/VvZg==} + engines: {node: '>=0.2.6'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.17.0: + resolution: {integrity: sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base-64@0.1.0: + resolution: {integrity: sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + better-sqlite3@12.10.0: + resolution: {integrity: sha512-CyzaZRQKyHkB2ZInfTTl2nvT33EbDpjkLEbE8/Zck3Ll6O0qqvuGdrJ45HgtH+HykRg88ITY3AdreBGN70aBSQ==} + engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x || 26.x} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + bson@7.2.0: + resolution: {integrity: sha512-YCEo7KjMlbNlyHhz7zAZNDpIpQbd+wOEHJYezv0nMYTn4x31eIUM2yomNNubclAt63dObUzKHWsBLJ9QcZNSnQ==} + engines: {node: '>=20.19.0'} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cloudflare@4.5.0: + resolution: {integrity: sha512-fPcbPKx4zF45jBvQ0z7PCdgejVAPBBCZxwqk1k7krQNfpM07Cfj97/Q6wBzvYqlWXx/zt1S9+m8vnfCe06umbQ==} + + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + compromise@14.15.1: + resolution: {integrity: sha512-9F3UkUaEU1PPz2fgStkE/TI4tk++0wHxS8xfWq9PQWL/v28dy8bEcPVVSLh3dISIRD7PEhJ8YTzHRKF8y9tnLA==} + engines: {node: '>=12.0.0'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + digest-fetch@1.3.0: + resolution: {integrity: sha512-CGJuv6iKNM7QyZlM2T3sPAdZWd/p9zQiRNS9G+9COUCwzWFTs0Xp8NF5iePx7wtvhDykReiRRrSeNb4oMmB8lA==} + + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + efrt@2.7.0: + resolution: {integrity: sha512-/RInbCy1d4P6Zdfa+TMVsf/ufZVotat5hCw3QXmWtjU+3pFEOvOQ7ibo3aIxyCJw2leIeAMjmPj+1SLJiCpdrQ==} + engines: {node: '>=12.0.0'} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-xml-builder@1.2.0: + resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} + + fast-xml-parser@5.7.3: + resolution: {integrity: sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==} + hasBin: true + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gaxios@7.1.5: + resolution: {integrity: sha512-5FZy72Rh8LhtjmvDrKkI+lVhrsQrVKVsItxMoDm5mNQE+xR0WVIIs+jzPSJgBvKVsLi24fZhXJIsNI0bihDzFg==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + + google-auth-library@10.7.0: + resolution: {integrity: sha512-QpTAbNJ36TliZLx3TTtahR8HG0hN9RllL1e3FymOvQSIKK8JmgV58H924ub2wa2DsS3ANjjP1Aw1N+Ramc8hqQ==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + grad-school@0.0.5: + resolution: {integrity: sha512-rXunEHF9M9EkMydTBux7+IryYXEZinRk6g8OBOGDBzo/qWJjhTxy86i5q7lQYpCLHN8Sqv1XX3OIOc7ka2gtvQ==} + engines: {node: '>=8.0.0'} + + groq-sdk@0.3.0: + resolution: {integrity: sha512-Cdgjh4YoSBE2X4S9sxPGXaAy1dlN4bRtAaDZ3cnq+XsxhhN9WSBeHF64l7LWwuD5ntmw7YC5Vf4Ff1oHCg1LOg==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + + hosted-git-info@9.0.3: + resolution: {integrity: sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==} + engines: {node: ^20.17.0 || >=22.9.0} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + iceberg-js@0.8.1: + resolution: {integrity: sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==} + engines: {node: '>=20.0.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-tiktoken@1.0.21: + resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} + engines: {node: '>=12', npm: '>=6'} + + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + kareem@3.3.0: + resolution: {integrity: sha512-kpSuLD3/7RenBnjnJdOHXCKC8dTd1JzeOiJhN0necWWci6cC+qX+VuwPnMVgb+a4+KNJSfgqahpnfWaeDXCimw==} + engines: {node: '>=18.0.0'} + + langsmith@0.7.5: + resolution: {integrity: sha512-OeD6+yKtWwy6sAboq25kD5DICzYv7j2KgtV2n4LsJ8nU2LpEdt1UwbjA6BON/zTggmS/YjV2TtLTHd7VEJhtEA==} + peerDependencies: + '@opentelemetry/api': '*' + '@opentelemetry/exporter-trace-otlp-proto': '*' + '@opentelemetry/sdk-trace-base': '*' + openai: '*' + ws: '>=7' + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@opentelemetry/exporter-trace-otlp-proto': + optional: true + '@opentelemetry/sdk-trace-base': + optional: true + openai: + optional: true + ws: + optional: true + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + lru-cache@11.5.1: + resolution: {integrity: sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==} + engines: {node: 20 || >=22} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + marked@15.0.12: + resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==} + engines: {node: '>= 18'} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + + mem0ai@3.0.6: + resolution: {integrity: sha512-X1KbCVE5351qpJ6X2KXFhQJiW+dqoHj1otA66DSdXtIEO1uXuIdyeTKeURdAH+wjXtIcFa08ylL2meA1pBk9Iw==} + engines: {node: '>=18'} + peerDependencies: + '@anthropic-ai/sdk': ^0.40.1 + '@azure/identity': ^4.0.0 + '@azure/search-documents': ^12.0.0 + '@cloudflare/workers-types': ^4.20250504.0 + '@google/genai': ^1.40.0 + '@langchain/core': ^1.1.47 + '@mistralai/mistralai': ^1.5.2 + '@qdrant/js-client-rest': ^1.18.0 + '@supabase/supabase-js': ^2.49.1 + '@types/jest': 29.5.14 + '@types/pg': 8.11.0 + better-sqlite3: ^12.6.2 + cloudflare: ^4.2.0 + compromise: ^14.0.0 + groq-sdk: 0.3.0 + natural: ^8.0.1 + ollama: ^0.5.14 + pg: 8.11.3 + redis: ^4.6.13 + + memjs@1.3.2: + resolution: {integrity: sha512-qUEg2g8vxPe+zPn09KidjIStHPtoBO8Cttm8bgJFWWabbsjQ9Av9Ky+6UcvKx6ue0LLb/LEhtcyQpRyKfzeXcg==} + engines: {node: '>=0.10.0'} + + memory-pager@1.5.0: + resolution: {integrity: sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + mongodb-connection-string-url@7.0.1: + resolution: {integrity: sha512-h0AZ9A7IDVwwHyMxmdMXKy+9oNlF0zFoahHiX3vQ8e3KFcSP3VmsmfvtRSuLPxmyv2vjIDxqty8smTgie/SNRQ==} + engines: {node: '>=20.19.0'} + + mongodb@7.2.0: + resolution: {integrity: sha512-F/2+BMZtLVhY30ioZp0dAmZ+IRZMBqI+nrv6t5+9/1AIwCa8sMRC3jBf81lpxMhnZgqq8CoUD503Z1oZWq1/sw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@aws-sdk/credential-providers': ^3.806.0 + '@mongodb-js/zstd': ^7.0.0 + gcp-metadata: ^7.0.1 + kerberos: ^7.0.0 + mongodb-client-encryption: '>=7.0.0 <7.1.0' + snappy: ^7.3.2 + socks: ^2.8.6 + peerDependenciesMeta: + '@aws-sdk/credential-providers': + optional: true + '@mongodb-js/zstd': + optional: true + gcp-metadata: + optional: true + kerberos: + optional: true + mongodb-client-encryption: + optional: true + snappy: + optional: true + socks: + optional: true + + mongoose@9.6.3: + resolution: {integrity: sha512-vI6dTTlQnfMCyyQ5TrvhG0bCRs4dq5e1uFNPtOOWsOhn0fSg8AoIHjfyyCYr8aybyvPs845dRHGxsC3w/fHcBA==} + engines: {node: '>=20.19.0'} + + mpath@0.9.0: + resolution: {integrity: sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==} + engines: {node: '>=4.0.0'} + + mquery@6.0.0: + resolution: {integrity: sha512-b2KQNsmgtkscfeDgkYMcWGn9vZI9YoXh802VDEwE6qc50zxBFQ0Oo8ROkawbPAsXCY1/Z1yp0MagqsZStPWJjw==} + engines: {node: '>=20.19.0'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mustache@4.2.0: + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} + hasBin: true + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + natural@8.1.1: + resolution: {integrity: sha512-Ucb+lsUcGxUqu3rn8cwHjT6gJQosO63nIX/aBQXB3+IDkNbFV7PuviysO+Rzz3aKn7PZhPj3bNF4PS9gDVjYCQ==} + engines: {node: '>=0.4.10'} + + node-abi@3.92.0: + resolution: {integrity: sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==} + engines: {node: '>=10'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + + obug@2.1.2: + resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==} + engines: {node: '>=12.20.0'} + + ollama@0.5.18: + resolution: {integrity: sha512-lTFqTf9bo7Cd3hpF6CviBe/DEhewjoZYd9N/uCe7O20qYTvGqrNOFOBDj3lbZgFWHUgDv5EeyusYxsZSLS8nvg==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + + openai@4.104.0: + resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + openai@6.26.0: + resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + + p-queue@6.6.2: + resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} + engines: {node: '>=8'} + + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + + p-timeout@3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + + path-expression-matcher@1.5.0: + resolution: {integrity: sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==} + engines: {node: '>=14.0.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pg-cloudflare@1.4.0: + resolution: {integrity: sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==} + + pg-connection-string@2.13.0: + resolution: {integrity: sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + + pg-pool@3.14.0: + resolution: {integrity: sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.14.0: + resolution: {integrity: sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg-types@4.1.0: + resolution: {integrity: sha512-o2XFanIMy/3+mThw69O8d4n1E5zsLhdO+OPqswezu7Z5ekP4hYDqlDjlmOpYMbzY2Br0ufCwJLdDIXeNVwcWFg==} + engines: {node: '>=10'} + + pg@8.21.0: + resolution: {integrity: sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==} + engines: {node: '>= 16.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-array@3.0.4: + resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==} + engines: {node: '>=12'} + + postgres-bytea@1.0.1: + resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} + engines: {node: '>=0.10.0'} + + postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + + postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. + hasBin: true + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + proper-lockfile@4.1.2: + resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==} + + protobufjs@7.6.2: + resolution: {integrity: sha512-N9EiLovGEQOJSPF26Ij7qUGvahfEnq0eeYZ02aigIedkmz1qZSwjnP9SBITHJuF/6MYbIW4HDN8zdYjsjqJKXQ==} + engines: {node: '>=12.0.0'} + + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + redis@5.12.1: + resolution: {integrity: sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==} + engines: {node: '>= 18.19.0'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup@4.61.1: + resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + + semver@7.8.3: + resolution: {integrity: sha512-wnilbGyMxzbY7dNOl7jpKbLSjcfeweJWU5j4+u5qW+6/wuGD9KzIGOyZnQVSBM9E7DtWaaH3CyHkppYrKYoxwg==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + sift@17.1.3: + resolution: {integrity: sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + sparse-bitfield@3.0.3: + resolution: {integrity: sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + + stopwords-iso@1.1.0: + resolution: {integrity: sha512-I6GPS/E0zyieHehMRPQcqkiBMJKGgLta+1hREixhoLPqEA0AlVFiC43dl8uPpmkkeRdDMzYRWFWk5/l9x7nmNg==} + engines: {node: '>=0.10.0'} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strnum@2.3.0: + resolution: {integrity: sha512-ums3KNd42PGyx5xaoVTO1mjU1bH3NpY4vsrVlnv9PNGqQj8wd7rJ6nEypLrJ7z5vxK5RP0yMLo6J/Gsm62DI5Q==} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + suffix-thumb@5.0.2: + resolution: {integrity: sha512-I5PWXAFKx3FYnI9a+dQMWNqTxoRt6vdBdb0O+BJ1sxXCWtSoQCusc13E58f+9p4MYx/qCnEMkD5jac6K2j3dgA==} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + sylvester@0.0.21: + resolution: {integrity: sha512-yUT0ukFkFEt4nb+NY+n2ag51aS/u9UHXoZw+A4jgD77/jzZsBoSDHuqysrVCBC4CYR4TYvUJq54ONpXgDBH8tA==} + engines: {node: '>=0.2.6'} + + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + typebox@1.1.38: + resolution: {integrity: sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==} + + typebox@1.2.3: + resolution: {integrity: sha512-EdFz/9FGvhQK2NmjZjSLri+nd5oMH+t/46/6lueEPbeHmS9WbWOz5IayPyLw0HHIyOWfo+wPrQGcAEQ+GsXc/w==} + + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + underscore@1.13.8: + resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + + undici@6.26.0: + resolution: {integrity: sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==} + engines: {node: '>=18.17'} + + undici@8.3.0: + resolution: {integrity: sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q==} + engines: {node: '>=22.19.0'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@13.0.2: + resolution: {integrity: sha512-vzi9uRZ926x4XV73S/4qQaTwPXM2JBj6/6lI/byHH1jOpCzb0zDbfytgA9LcN/hzb2l7WQSQnxITOVx5un/wGw==} + hasBin: true + + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.8: + resolution: {integrity: sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.8 + '@vitest/browser-preview': 4.1.8 + '@vitest/browser-webdriverio': 4.1.8 + '@vitest/coverage-istanbul': 4.1.8 + '@vitest/coverage-v8': 4.1.8 + '@vitest/ui': 4.1.8 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + wordnet-db@3.1.14: + resolution: {integrity: sha512-zVyFsvE+mq9MCmwXUWHIcpfbrHHClZWZiVOzKSxNJruIcFn2RbY55zkhiAMMxM8zCVSmtNiViq8FsAZSFpMYag==} + engines: {node: '>=0.6.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + + xml-naming@0.1.0: + resolution: {integrity: sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==} + engines: {node: '>=16.0.0'} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + +snapshots: + + '@anthropic-ai/sdk@0.91.1(zod@3.25.76)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 3.25.76 + + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.12 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.12 + '@aws-sdk/util-locate-window': 3.965.7 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.12 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.12 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.19 + '@aws-sdk/credential-provider-node': 3.972.53 + '@aws-sdk/eventstream-handler-node': 3.972.21 + '@aws-sdk/middleware-eventstream': 3.972.17 + '@aws-sdk/middleware-websocket': 3.972.27 + '@aws-sdk/token-providers': 3.1048.0 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/fetch-http-handler': 5.4.6 + '@smithy/node-http-handler': 4.7.3 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/core@3.974.19': + dependencies: + '@aws-sdk/types': 3.973.12 + '@aws-sdk/xml-builder': 3.972.29 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/core': 3.24.6 + '@smithy/signature-v4': 5.4.6 + '@smithy/types': 4.14.3 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.45': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.47': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/fetch-http-handler': 5.4.6 + '@smithy/node-http-handler': 4.7.7 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.51': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/credential-provider-env': 3.972.45 + '@aws-sdk/credential-provider-http': 3.972.47 + '@aws-sdk/credential-provider-login': 3.972.50 + '@aws-sdk/credential-provider-process': 3.972.45 + '@aws-sdk/credential-provider-sso': 3.972.50 + '@aws-sdk/credential-provider-web-identity': 3.972.50 + '@aws-sdk/nested-clients': 3.997.18 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/credential-provider-imds': 4.3.8 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.50': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/nested-clients': 3.997.18 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.53': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.45 + '@aws-sdk/credential-provider-http': 3.972.47 + '@aws-sdk/credential-provider-ini': 3.972.51 + '@aws-sdk/credential-provider-process': 3.972.45 + '@aws-sdk/credential-provider-sso': 3.972.50 + '@aws-sdk/credential-provider-web-identity': 3.972.50 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/credential-provider-imds': 4.3.8 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.45': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.50': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/nested-clients': 3.997.18 + '@aws-sdk/token-providers': 3.1064.0 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.50': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/nested-clients': 3.997.18 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/eventstream-handler-node@3.972.21': + dependencies: + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.17': + dependencies: + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.27': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/fetch-http-handler': 5.4.6 + '@smithy/signature-v4': 5.4.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.18': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.19 + '@aws-sdk/signature-v4-multi-region': 3.996.33 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/fetch-http-handler': 5.4.6 + '@smithy/node-http-handler': 4.7.7 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.33': + dependencies: + '@aws-sdk/types': 3.973.12 + '@smithy/signature-v4': 5.4.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1048.0': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/nested-clients': 3.997.18 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1064.0': + dependencies: + '@aws-sdk/core': 3.974.19 + '@aws-sdk/nested-clients': 3.997.18 + '@aws-sdk/types': 3.973.12 + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/types@3.973.12': + dependencies: + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.7': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.29': + dependencies: + '@smithy/types': 4.14.3 + fast-xml-parser: 5.7.3 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.4': {} + + '@azure/abort-controller@2.1.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-auth@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-client@1.10.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-rest-pipeline': 1.24.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-http-compat@2.4.0(@azure/core-client@1.10.2)(@azure/core-rest-pipeline@1.24.0)': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-client': 1.10.2 + '@azure/core-rest-pipeline': 1.24.0 + + '@azure/core-paging@1.6.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-rest-pipeline@1.24.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@typespec/ts-http-runtime': 0.3.6 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-tracing@1.3.1': + dependencies: + tslib: 2.8.1 + + '@azure/core-util@1.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@typespec/ts-http-runtime': 0.3.6 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/identity@4.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.2 + '@azure/core-rest-pipeline': 1.24.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@azure/msal-browser': 5.12.0 + '@azure/msal-node': 5.2.3 + open: 10.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/logger@1.3.0': + dependencies: + '@typespec/ts-http-runtime': 0.3.6 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/msal-browser@5.12.0': + dependencies: + '@azure/msal-common': 16.7.0 + + '@azure/msal-common@16.7.0': {} + + '@azure/msal-node@5.2.3': + dependencies: + '@azure/msal-common': 16.7.0 + jsonwebtoken: 9.0.3 + + '@azure/search-documents@12.2.0': + dependencies: + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.2 + '@azure/core-http-compat': 2.4.0(@azure/core-client@1.10.2)(@azure/core-rest-pipeline@1.24.0) + '@azure/core-paging': 1.6.2 + '@azure/core-rest-pipeline': 1.24.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + events: 3.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/runtime@7.29.7': {} + + '@cfworker/json-schema@4.1.1': {} + + '@cloudflare/workers-types@4.20260609.1': {} + + '@earendil-works/pi-agent-core@0.79.0(ws@8.21.0)(zod@3.25.76)': + dependencies: + '@earendil-works/pi-ai': 0.79.0(ws@8.21.0)(zod@3.25.76) + ignore: 7.0.5 + typebox: 1.1.38 + yaml: 2.9.0 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-ai@0.79.0(ws@8.21.0)(zod@3.25.76)': + dependencies: + '@anthropic-ai/sdk': 0.91.1(zod@3.25.76) + '@aws-sdk/client-bedrock-runtime': 3.1048.0 + '@google/genai': 1.52.0 + '@mistralai/mistralai': 2.2.1 + '@smithy/node-http-handler': 4.7.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + openai: 6.26.0(ws@8.21.0)(zod@3.25.76) + partial-json: 0.1.7 + typebox: 1.1.38 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-coding-agent@0.79.0(ws@8.21.0)(zod@3.25.76)': + dependencies: + '@earendil-works/pi-agent-core': 0.79.0(ws@8.21.0)(zod@3.25.76) + '@earendil-works/pi-ai': 0.79.0(ws@8.21.0)(zod@3.25.76) + '@earendil-works/pi-tui': 0.79.0 + '@silvia-odwyer/photon-node': 0.3.4 + chalk: 5.6.2 + cross-spawn: 7.0.6 + diff: 8.0.4 + glob: 13.0.6 + highlight.js: 10.7.3 + hosted-git-info: 9.0.3 + ignore: 7.0.5 + jiti: 2.7.0 + minimatch: 10.2.5 + proper-lockfile: 4.1.2 + typebox: 1.1.38 + undici: 8.3.0 + yaml: 2.9.0 + optionalDependencies: + '@mariozechner/clipboard': 0.3.9 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@earendil-works/pi-tui@0.79.0': + dependencies: + get-east-asian-width: 1.6.0 + marked: 15.0.12 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@google/genai@1.52.0': + dependencies: + google-auth-library: 10.7.0 + p-retry: 4.6.2 + protobufjs: 7.6.2 + ws: 8.21.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.10 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 25.9.2 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@langchain/core@1.1.48(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0)': + dependencies: + '@cfworker/json-schema': 4.1.1 + '@standard-schema/spec': 1.1.0 + js-tiktoken: 1.0.21 + langsmith: 0.7.5(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0) + mustache: 4.2.0 + p-queue: 6.6.2 + zod: 4.4.3 + transitivePeerDependencies: + - '@opentelemetry/api' + - '@opentelemetry/exporter-trace-otlp-proto' + - '@opentelemetry/sdk-trace-base' + - openai + - ws + + '@mariozechner/clipboard-darwin-arm64@0.3.9': + optional: true + + '@mariozechner/clipboard-darwin-universal@0.3.9': + optional: true + + '@mariozechner/clipboard-darwin-x64@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-arm64-gnu@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-arm64-musl@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-riscv64-gnu@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-x64-gnu@0.3.9': + optional: true + + '@mariozechner/clipboard-linux-x64-musl@0.3.9': + optional: true + + '@mariozechner/clipboard-win32-arm64-msvc@0.3.9': + optional: true + + '@mariozechner/clipboard-win32-x64-msvc@0.3.9': + optional: true + + '@mariozechner/clipboard@0.3.9': + optionalDependencies: + '@mariozechner/clipboard-darwin-arm64': 0.3.9 + '@mariozechner/clipboard-darwin-universal': 0.3.9 + '@mariozechner/clipboard-darwin-x64': 0.3.9 + '@mariozechner/clipboard-linux-arm64-gnu': 0.3.9 + '@mariozechner/clipboard-linux-arm64-musl': 0.3.9 + '@mariozechner/clipboard-linux-riscv64-gnu': 0.3.9 + '@mariozechner/clipboard-linux-x64-gnu': 0.3.9 + '@mariozechner/clipboard-linux-x64-musl': 0.3.9 + '@mariozechner/clipboard-win32-arm64-msvc': 0.3.9 + '@mariozechner/clipboard-win32-x64-msvc': 0.3.9 + optional: true + + '@mistralai/mistralai@2.2.1': + dependencies: + ws: 8.21.0 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@mongodb-js/saslprep@1.4.11': + dependencies: + sparse-bitfield: 3.0.3 + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@nodable/entities@2.1.1': {} + + '@oxc-project/types@0.133.0': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/inquire@1.1.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.1': {} + + '@qdrant/js-client-rest@1.18.0(typescript@6.0.3)': + dependencies: + '@qdrant/openapi-typescript-fetch': 1.2.6 + typescript: 6.0.3 + undici: 6.26.0 + + '@qdrant/openapi-typescript-fetch@1.2.6': {} + + '@redis/bloom@5.12.1(@redis/client@5.12.1)': + dependencies: + '@redis/client': 5.12.1 + + '@redis/client@5.12.1': + dependencies: + cluster-key-slot: 1.1.2 + + '@redis/json@5.12.1(@redis/client@5.12.1)': + dependencies: + '@redis/client': 5.12.1 + + '@redis/search@5.12.1(@redis/client@5.12.1)': + dependencies: + '@redis/client': 5.12.1 + + '@redis/time-series@5.12.1(@redis/client@5.12.1)': + dependencies: + '@redis/client': 5.12.1 + + '@rolldown/binding-android-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@rollup/rollup-android-arm-eabi@4.61.1': + optional: true + + '@rollup/rollup-android-arm64@4.61.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.61.1': + optional: true + + '@rollup/rollup-darwin-x64@4.61.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.61.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.61.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.61.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.61.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.61.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.61.1': + optional: true + + '@rollup/rollup-openbsd-x64@4.61.1': + optional: true + + '@rollup/rollup-openharmony-arm64@4.61.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.61.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.61.1': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.61.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.61.1': + optional: true + + '@silvia-odwyer/photon-node@0.3.4': {} + + '@sinclair/typebox@0.27.10': {} + + '@smithy/core@3.24.6': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.3.8': + dependencies: + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.4.6': + dependencies: + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/node-http-handler@4.7.3': + dependencies: + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.7.7': + dependencies: + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@smithy/signature-v4@5.4.6': + dependencies: + '@smithy/core': 3.24.6 + '@smithy/types': 4.14.3 + tslib: 2.8.1 + + '@smithy/types@4.14.3': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@standard-schema/spec@1.1.0': {} + + '@supabase/auth-js@2.108.0': + dependencies: + tslib: 2.8.1 + + '@supabase/functions-js@2.108.0': + dependencies: + tslib: 2.8.1 + + '@supabase/phoenix@0.4.2': {} + + '@supabase/postgrest-js@2.108.0': + dependencies: + tslib: 2.8.1 + + '@supabase/realtime-js@2.108.0': + dependencies: + '@supabase/phoenix': 0.4.2 + tslib: 2.8.1 + + '@supabase/storage-js@2.108.0': + dependencies: + iceberg-js: 0.8.1 + tslib: 2.8.1 + + '@supabase/supabase-js@2.108.0': + dependencies: + '@supabase/auth-js': 2.108.0 + '@supabase/functions-js': 2.108.0 + '@supabase/postgrest-js': 2.108.0 + '@supabase/realtime-js': 2.108.0 + '@supabase/storage-js': 2.108.0 + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.9': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 25.9.2 + form-data: 4.0.5 + + '@types/node@18.19.130': + dependencies: + undici-types: 5.26.5 + + '@types/node@25.9.2': + dependencies: + undici-types: 7.24.6 + + '@types/pg@8.11.0': + dependencies: + '@types/node': 25.9.2 + pg-protocol: 1.14.0 + pg-types: 4.1.0 + + '@types/retry@0.12.0': {} + + '@types/stack-utils@2.0.3': {} + + '@types/webidl-conversions@7.0.3': {} + + '@types/whatwg-url@13.0.0': + dependencies: + '@types/webidl-conversions': 7.0.3 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typespec/ts-http-runtime@0.3.6': + dependencies: + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@vitest/expect@4.1.8': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.8(vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0))': + dependencies: + '@vitest/spy': 4.1.8 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0) + + '@vitest/pretty-format@4.1.8': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.8': + dependencies: + '@vitest/utils': 4.1.8 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.8': + dependencies: + '@vitest/pretty-format': 4.1.8 + '@vitest/utils': 4.1.8 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.8': {} + + '@vitest/utils@4.1.8': + dependencies: + '@vitest/pretty-format': 4.1.8 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + acorn@8.16.0: {} + + afinn-165-financialmarketnews@3.0.0: {} + + afinn-165@2.0.2: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + agent-base@7.1.4: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + any-promise@1.3.0: {} + + apparatus@0.0.10: + dependencies: + sylvester: 0.0.21 + + assertion-error@2.0.1: {} + + asynckit@0.4.0: {} + + axios@1.17.0: + dependencies: + follow-redirects: 1.16.0 + form-data: 4.0.5 + https-proxy-agent: 5.0.1 + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + + balanced-match@4.0.4: {} + + base-64@0.1.0: {} + + base64-js@1.5.1: {} + + better-sqlite3@12.10.0: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + + bignumber.js@9.3.1: {} + + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + bowser@2.14.1: {} + + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + bson@7.2.0: {} + + buffer-equal-constant-time@1.0.1: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + bundle-require@5.1.0(esbuild@0.27.7): + dependencies: + esbuild: 0.27.7 + load-tsconfig: 0.2.5 + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + chai@6.2.2: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + charenc@0.0.2: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chownr@1.1.4: {} + + ci-info@3.9.0: {} + + cloudflare@4.5.0: + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + transitivePeerDependencies: + - encoding + + cluster-key-slot@1.1.2: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@4.1.1: {} + + compromise@14.15.1: + dependencies: + efrt: 2.7.0 + grad-school: 0.0.5 + suffix-thumb: 5.0.2 + + confbox@0.1.8: {} + + consola@3.4.2: {} + + convert-source-map@2.0.0: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + crypt@0.0.2: {} + + data-uri-to-buffer@4.0.1: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + define-lazy-prop@3.0.0: {} + + delayed-stream@1.0.0: {} + + detect-libc@2.1.2: {} + + diff-sequences@29.6.3: {} + + diff@8.0.4: {} + + digest-fetch@1.3.0: + dependencies: + base-64: 0.1.0 + md5: 2.3.0 + + dotenv@17.4.2: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + efrt@2.7.0: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.1.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + escape-string-regexp@2.0.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + event-target-shim@5.0.1: {} + + eventemitter3@4.0.7: {} + + events@3.3.0: {} + + expand-template@2.0.3: {} + + expect-type@1.3.0: {} + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + extend@3.0.2: {} + + fast-xml-builder@1.2.0: + dependencies: + path-expression-matcher: 1.5.0 + xml-naming: 0.1.0 + + fast-xml-parser@5.7.3: + dependencies: + '@nodable/entities': 2.1.1 + fast-xml-builder: 1.2.0 + path-expression-matcher: 1.5.0 + strnum: 2.3.0 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + file-uri-to-path@1.0.0: {} + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.2 + rollup: 4.61.1 + + follow-redirects@1.16.0: {} + + form-data-encoder@1.7.2: {} + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + fs-constants@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gaxios@7.1.5: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.1.5 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + + get-east-asian-width@1.6.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + github-from-package@0.0.0: {} + + glob@13.0.6: + dependencies: + minimatch: 10.2.5 + minipass: 7.1.3 + path-scurry: 2.0.2 + + google-auth-library@10.7.0: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.1.5 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + grad-school@0.0.5: {} + + groq-sdk@0.3.0: + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + digest-fetch: 1.3.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + web-streams-polyfill: 3.3.3 + transitivePeerDependencies: + - encoding + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + highlight.js@10.7.3: {} + + hosted-git-info@9.0.3: + dependencies: + lru-cache: 11.5.1 + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + iceberg-js@0.8.1: {} + + ieee754@1.2.1: {} + + ignore@7.0.5: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + is-buffer@1.1.6: {} + + is-docker@3.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-number@7.0.0: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + isexe@2.0.0: {} + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.29.7 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 25.9.2 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.2 + + jiti@2.7.0: {} + + joycon@3.1.1: {} + + js-tiktoken@1.0.21: + dependencies: + base64-js: 1.5.1 + + js-tokens@4.0.0: {} + + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.7 + ts-algebra: 2.0.0 + + jsonwebtoken@9.0.3: + dependencies: + jws: 4.0.1 + lodash.includes: 4.3.0 + lodash.isboolean: 3.0.3 + lodash.isinteger: 4.0.4 + lodash.isnumber: 3.0.3 + lodash.isplainobject: 4.0.6 + lodash.isstring: 4.0.1 + lodash.once: 4.1.1 + ms: 2.1.3 + semver: 7.8.3 + + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + kareem@3.3.0: {} + + langsmith@0.7.5(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0): + dependencies: + p-queue: 6.6.2 + optionalDependencies: + openai: 6.26.0(ws@8.21.0)(zod@3.25.76) + ws: 8.21.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + load-tsconfig@0.2.5: {} + + lodash.includes@4.3.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isinteger@4.0.4: {} + + lodash.isnumber@3.0.3: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isstring@4.0.1: {} + + lodash.once@4.1.1: {} + + long@5.3.2: {} + + lru-cache@11.5.1: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + marked@15.0.12: {} + + math-intrinsics@1.1.0: {} + + md5@2.3.0: + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + + mem0ai@3.0.6(@anthropic-ai/sdk@0.91.1(zod@3.25.76))(@azure/identity@4.13.1)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260609.1)(@google/genai@1.52.0)(@langchain/core@1.1.48(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0))(@mistralai/mistralai@2.2.1)(@qdrant/js-client-rest@1.18.0(typescript@6.0.3))(@supabase/supabase-js@2.108.0)(@types/jest@29.5.14)(@types/pg@8.11.0)(better-sqlite3@12.10.0)(cloudflare@4.5.0)(compromise@14.15.1)(groq-sdk@0.3.0)(natural@8.1.1)(ollama@0.5.18)(pg@8.21.0)(redis@5.12.1)(ws@8.21.0): + dependencies: + '@anthropic-ai/sdk': 0.91.1(zod@3.25.76) + '@azure/identity': 4.13.1 + '@azure/search-documents': 12.2.0 + '@cloudflare/workers-types': 4.20260609.1 + '@google/genai': 1.52.0 + '@langchain/core': 1.1.48(openai@6.26.0(ws@8.21.0)(zod@3.25.76))(ws@8.21.0) + '@mistralai/mistralai': 2.2.1 + '@qdrant/js-client-rest': 1.18.0(typescript@6.0.3) + '@supabase/supabase-js': 2.108.0 + '@types/jest': 29.5.14 + '@types/pg': 8.11.0 + axios: 1.17.0 + better-sqlite3: 12.10.0 + cloudflare: 4.5.0 + compromise: 14.15.1 + groq-sdk: 0.3.0 + natural: 8.1.1 + ollama: 0.5.18 + openai: 4.104.0(ws@8.21.0)(zod@3.25.76) + pg: 8.21.0 + redis: 5.12.1 + uuid: 9.0.1 + zod: 3.25.76 + transitivePeerDependencies: + - debug + - encoding + - supports-color + - ws + + memjs@1.3.2: {} + + memory-pager@1.5.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-response@3.1.0: {} + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.6 + + minimist@1.2.8: {} + + minipass@7.1.3: {} + + mkdirp-classic@0.5.3: {} + + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + mongodb-connection-string-url@7.0.1: + dependencies: + '@types/whatwg-url': 13.0.0 + whatwg-url: 14.2.0 + + mongodb@7.2.0: + dependencies: + '@mongodb-js/saslprep': 1.4.11 + bson: 7.2.0 + mongodb-connection-string-url: 7.0.1 + + mongoose@9.6.3: + dependencies: + kareem: 3.3.0 + mongodb: 7.2.0 + mpath: 0.9.0 + mquery: 6.0.0 + ms: 2.1.3 + sift: 17.1.3 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - snappy + - socks + + mpath@0.9.0: {} + + mquery@6.0.0: {} + + ms@2.1.3: {} + + mustache@4.2.0: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.12: {} + + napi-build-utils@2.0.0: {} + + natural@8.1.1: + dependencies: + afinn-165: 2.0.2 + afinn-165-financialmarketnews: 3.0.0 + apparatus: 0.0.10 + dotenv: 17.4.2 + memjs: 1.3.2 + mongoose: 9.6.3 + pg: 8.21.0 + redis: 5.12.1 + safe-stable-stringify: 2.5.0 + stopwords-iso: 1.1.0 + sylvester: 0.0.21 + underscore: 1.13.8 + uuid: 13.0.2 + wordnet-db: 3.1.14 + transitivePeerDependencies: + - '@aws-sdk/credential-providers' + - '@mongodb-js/zstd' + - '@node-rs/xxhash' + - '@opentelemetry/api' + - gcp-metadata + - kerberos + - mongodb-client-encryption + - pg-native + - snappy + - socks + + node-abi@3.92.0: + dependencies: + semver: 7.8.3 + + node-domexception@1.0.0: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + object-assign@4.1.1: {} + + obuf@1.1.2: {} + + obug@2.1.2: {} + + ollama@0.5.18: + dependencies: + whatwg-fetch: 3.6.20 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + open@10.2.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + + openai@4.104.0(ws@8.21.0)(zod@3.25.76): + dependencies: + '@types/node': 18.19.130 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + optionalDependencies: + ws: 8.21.0 + zod: 3.25.76 + transitivePeerDependencies: + - encoding + + openai@6.26.0(ws@8.21.0)(zod@3.25.76): + optionalDependencies: + ws: 8.21.0 + zod: 3.25.76 + + p-finally@1.0.0: {} + + p-queue@6.6.2: + dependencies: + eventemitter3: 4.0.7 + p-timeout: 3.2.0 + + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + + p-timeout@3.2.0: + dependencies: + p-finally: 1.0.0 + + partial-json@0.1.7: {} + + path-expression-matcher@1.5.0: {} + + path-key@3.1.1: {} + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.1 + minipass: 7.1.3 + + pathe@2.0.3: {} + + pg-cloudflare@1.4.0: + optional: true + + pg-connection-string@2.13.0: {} + + pg-int8@1.0.1: {} + + pg-numeric@1.0.2: {} + + pg-pool@3.14.0(pg@8.21.0): + dependencies: + pg: 8.21.0 + + pg-protocol@1.14.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.1 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg-types@4.1.0: + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.4 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + + pg@8.21.0: + dependencies: + pg-connection-string: 2.13.0 + pg-pool: 3.14.0(pg@8.21.0) + pg-protocol: 1.14.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.4.0 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pirates@4.0.7: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(yaml@2.9.0): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.7.0 + postcss: 8.5.15 + yaml: 2.9.0 + + postcss@8.5.15: + dependencies: + nanoid: 3.3.12 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postgres-array@2.0.0: {} + + postgres-array@3.0.4: {} + + postgres-bytea@1.0.1: {} + + postgres-bytea@3.0.0: + dependencies: + obuf: 1.1.2 + + postgres-date@1.0.7: {} + + postgres-date@2.1.0: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + + postgres-interval@3.0.0: {} + + postgres-range@1.1.4: {} + + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.1.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.92.0 + pump: 3.0.4 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.4 + tunnel-agent: 0.6.0 + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + proper-lockfile@4.1.2: + dependencies: + graceful-fs: 4.2.11 + retry: 0.12.0 + signal-exit: 3.0.7 + + protobufjs@7.6.2: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/inquire': 1.1.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.1 + '@types/node': 25.9.2 + long: 5.3.2 + + proxy-from-env@2.1.0: {} + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + punycode@2.3.1: {} + + rc@1.2.8: + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + + react-is@18.3.1: {} + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdirp@4.1.2: {} + + redis@5.12.1: + dependencies: + '@redis/bloom': 5.12.1(@redis/client@5.12.1) + '@redis/client': 5.12.1 + '@redis/json': 5.12.1(@redis/client@5.12.1) + '@redis/search': 5.12.1(@redis/client@5.12.1) + '@redis/time-series': 5.12.1(@redis/client@5.12.1) + transitivePeerDependencies: + - '@node-rs/xxhash' + - '@opentelemetry/api' + + resolve-from@5.0.0: {} + + retry@0.12.0: {} + + retry@0.13.1: {} + + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + + rollup@4.61.1: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.61.1 + '@rollup/rollup-android-arm64': 4.61.1 + '@rollup/rollup-darwin-arm64': 4.61.1 + '@rollup/rollup-darwin-x64': 4.61.1 + '@rollup/rollup-freebsd-arm64': 4.61.1 + '@rollup/rollup-freebsd-x64': 4.61.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 + '@rollup/rollup-linux-arm-musleabihf': 4.61.1 + '@rollup/rollup-linux-arm64-gnu': 4.61.1 + '@rollup/rollup-linux-arm64-musl': 4.61.1 + '@rollup/rollup-linux-loong64-gnu': 4.61.1 + '@rollup/rollup-linux-loong64-musl': 4.61.1 + '@rollup/rollup-linux-ppc64-gnu': 4.61.1 + '@rollup/rollup-linux-ppc64-musl': 4.61.1 + '@rollup/rollup-linux-riscv64-gnu': 4.61.1 + '@rollup/rollup-linux-riscv64-musl': 4.61.1 + '@rollup/rollup-linux-s390x-gnu': 4.61.1 + '@rollup/rollup-linux-x64-gnu': 4.61.1 + '@rollup/rollup-linux-x64-musl': 4.61.1 + '@rollup/rollup-openbsd-x64': 4.61.1 + '@rollup/rollup-openharmony-arm64': 4.61.1 + '@rollup/rollup-win32-arm64-msvc': 4.61.1 + '@rollup/rollup-win32-ia32-msvc': 4.61.1 + '@rollup/rollup-win32-x64-gnu': 4.61.1 + '@rollup/rollup-win32-x64-msvc': 4.61.1 + fsevents: 2.3.3 + + run-applescript@7.1.0: {} + + safe-buffer@5.2.1: {} + + safe-stable-stringify@2.5.0: {} + + semver@7.8.3: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + sift@17.1.3: {} + + siginfo@2.0.0: {} + + signal-exit@3.0.7: {} + + simple-concat@1.0.1: {} + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + + slash@3.0.0: {} + + source-map-js@1.2.1: {} + + source-map@0.7.6: {} + + sparse-bitfield@3.0.3: + dependencies: + memory-pager: 1.5.0 + + split2@4.2.0: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + stackback@0.0.2: {} + + std-env@4.1.0: {} + + stopwords-iso@1.1.0: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-json-comments@2.0.1: {} + + strnum@2.3.0: {} + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.17 + ts-interface-checker: 0.1.13 + + suffix-thumb@5.0.2: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + sylvester@0.0.21: {} + + tar-fs@2.1.4: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.4 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyexec@1.2.4: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyrainbow@3.1.0: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + tr46@0.0.3: {} + + tr46@5.1.1: + dependencies: + punycode: 2.3.1 + + tree-kill@1.2.2: {} + + ts-algebra@2.0.0: {} + + ts-interface-checker@0.1.13: {} + + tslib@2.8.1: {} + + tsup@8.5.1(jiti@2.7.0)(postcss@8.5.15)(typescript@6.0.3)(yaml@2.9.0): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.7) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.7 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.15)(yaml@2.9.0) + resolve-from: 5.0.0 + rollup: 4.61.1 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.15 + typescript: 6.0.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + + tunnel-agent@0.6.0: + dependencies: + safe-buffer: 5.2.1 + + typebox@1.1.38: {} + + typebox@1.2.3: {} + + typescript@6.0.3: {} + + ufo@1.6.4: {} + + underscore@1.13.8: {} + + undici-types@5.26.5: {} + + undici-types@7.24.6: {} + + undici@6.26.0: {} + + undici@8.3.0: {} + + util-deprecate@1.0.2: {} + + uuid@13.0.2: {} + + uuid@9.0.1: {} + + vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 25.9.2 + esbuild: 0.27.7 + fsevents: 2.3.3 + jiti: 2.7.0 + yaml: 2.9.0 + + vitest@4.1.8(@types/node@25.9.2)(vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0)): + dependencies: + '@vitest/expect': 4.1.8 + '@vitest/mocker': 4.1.8(vite@8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/pretty-format': 4.1.8 + '@vitest/runner': 4.1.8 + '@vitest/snapshot': 4.1.8 + '@vitest/spy': 4.1.8 + '@vitest/utils': 4.1.8 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.2 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.2.4 + tinyglobby: 0.2.17 + tinyrainbow: 3.1.0 + vite: 8.0.16(@types/node@25.9.2)(esbuild@0.27.7)(jiti@2.7.0)(yaml@2.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 25.9.2 + transitivePeerDependencies: + - msw + + web-streams-polyfill@3.3.3: {} + + web-streams-polyfill@4.0.0-beta.3: {} + + webidl-conversions@3.0.1: {} + + webidl-conversions@7.0.0: {} + + whatwg-fetch@3.6.20: {} + + whatwg-url@14.2.0: + dependencies: + tr46: 5.1.1 + webidl-conversions: 7.0.0 + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + wordnet-db@3.1.14: {} + + wrappy@1.0.2: {} + + ws@8.21.0: {} + + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + + xml-naming@0.1.0: {} + + xtend@4.0.2: {} + + yaml@2.9.0: {} + + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@3.25.76: {} + + zod@4.4.3: {} diff --git a/pi-agent-plugin/skills/context-loader/SKILL.md b/pi-agent-plugin/skills/context-loader/SKILL.md new file mode 100644 index 000000000..22c10b2c8 --- /dev/null +++ b/pi-agent-plugin/skills/context-loader/SKILL.md @@ -0,0 +1,47 @@ +--- +name: context-loader +description: Searches and injects relevant memories into context before starting work on a task or topic. Use when beginning a new task, switching context, or when past decisions, preferences, or knowledge need to be loaded. +--- + +# Context Loader + +Pre-fetches relevant memories to prime context before working on a task or topic. + +## When to use + +- Session start (auto-triggered by the extension's `before_agent_start` event) +- User starts work on a specific topic or area +- User says "what do we know about X" or "context for X" + +## Steps + +1. **Extract topics** from current message/task. Identify: subject areas, people mentioned, project names, goal references. + +2. **Run 2-4 parallel searches** using `mem0_memory` tool with `action="search"` and different query angles: + + | Query angle | Purpose | + |---|---| + | Topic/subject name | Relevant decisions and preferences | + | People mentioned | Relationship context | + | Project/goal references | Progress and background | + | Broad context | Catch-all for anything relevant | + +3. **Deduplicate** results by memory ID across all search responses. + +4. **Output compact context block** (max 10 memories): + +``` +context-loader: loaded memories for "" + - [decisions] [mem0:] + - [preferences] [mem0:] + - [lessons] [mem0:] +``` + +5. If **zero results**: output nothing. Don't announce empty context. + +## Constraints + +- **Read-only** — never modify or delete memories +- **Max 10 memories** returned (most relevant only) +- **Silent on empty** — only surfaces findings if relevant context exists +- Skip memories already visible in current session context diff --git a/pi-agent-plugin/skills/dream/SKILL.md b/pi-agent-plugin/skills/dream/SKILL.md new file mode 100644 index 000000000..21e9c5f43 --- /dev/null +++ b/pi-agent-plugin/skills/dream/SKILL.md @@ -0,0 +1,125 @@ +--- +name: dream +description: Consolidates stored memories by merging duplicates, resolving contradictions, and pruning stale entries. Use when memory count is high, search results feel noisy or repetitive, or periodic cleanup is needed to maintain memory quality. +--- + +# Dream — Memory Consolidation + +This skill performs a memory consolidation pass: it fetches all memories, identifies near-duplicates, flags contradictions, and prunes stale entries. All proposed changes are shown as a diff for user approval before anything is modified. + +**IMPORTANT: Execute steps strictly in order (1 -> 2 -> 3 -> 4 -> 5). Each step depends on the previous one. Do NOT run steps in parallel or skip ahead.** + +## Step 1: Fetch ALL Memories + +Use `mem0_memory` tool with `action="get_all"` to retrieve every memory. + +If zero memories are found, print: + +``` +No memories found. Nothing to consolidate. +``` + +...and stop. + +## Step 2: Analyze — Find Issues + +Work entirely in-memory; do not modify anything yet. + +Group memories by category. For each group, identify the following: + +### 2a. Near-duplicate pairs (merge candidates) + +Two memories are near-duplicates when they express the same fact but phrased differently (e.g., "Prefers morning meetings" and "Likes scheduling meetings early"). + +Heuristics — two memories are near-duplicates if **all** of these hold: +- If >60% of significant nouns/keywords overlap, treat as near-duplicate. +- Same category. +- Neither memory is pinned (content does not start with `[PINNED]`). + +For each qualifying pair, draft a merged version that is more complete than either original. + +### 2b. Contradictions + +Two memories contradict when they assert opposing facts about the same topic (e.g., "Prefers cats" vs. "Allergic to cats, prefers dogs"). + +Identify the likely winner: the more recent memory wins. Store both IDs and their content for user review. + +### 2c. Prune candidates + +A memory is a prune candidate when **any** of the following is true: + +1. It is older than 180 days AND has not been accessed recently. +2. Its content is extremely vague (fewer than 5 meaningful words). + +**Always skip memories where content starts with `[PINNED]`**, regardless of age. + +## Step 3: Print Diff Report + +Print a structured diff before making any changes: + +``` +## dream — consolidation report + +Merges (): + [mem0:] + [mem0:] -> "" + +Conflicts (): + [mem0:] vs [mem0:] — "" [A/B/skip] + +Prune (): + [mem0:] — , d old + +Proposed: merges, prunes, conflicts. Apply? [Y/n] +``` + +If there are zero total proposals, print: + +``` +Dream complete. No duplicate, contradictory, or stale memories found. +``` + +...and stop. + +## Step 4: Wait for User Input and Apply + +### 4a. Contradictions + +For each conflict pair, wait for the user to choose A, B, or skip. + +### 4b. Final confirmation + +After all conflict resolutions are collected, prompt: `Apply? [Y/n]` + +If the user declines, print `Cancelled. No changes made.` and stop. + +If confirmed, apply all changes: + +**Merges:** Delete both originals, add the merged version using `mem0_memory` with `action="add"`. + +**Contradictions (resolved):** Delete the loser using `mem0_memory` with `action="delete"`. + +**Prunes:** Delete each using `mem0_memory` with `action="delete"`. + +## Step 5: Print Summary + +``` +Dream complete — merged: , pruned: , conflicts resolved: , skipped: +``` + +## Auto mode + +When invoked with `--auto` (e.g., `/mem0-dream --auto`), run non-interactively: + +- **Merges**: applied automatically. +- **Prunes**: applied automatically. +- **Contradictions**: skipped — they require human judgment. + +Print a compact summary: +``` +[mem0-dream --auto] merged= pruned= conflicts_skipped= +``` + +## See also + +- `/mem0-forget` — targeted deletion of specific memories +- `/mem0-status` — quick health check diff --git a/pi-agent-plugin/skills/forget/SKILL.md b/pi-agent-plugin/skills/forget/SKILL.md new file mode 100644 index 000000000..cffeb5806 --- /dev/null +++ b/pi-agent-plugin/skills/forget/SKILL.md @@ -0,0 +1,53 @@ +--- +name: forget +description: Deletes memories by search query or memory ID with confirmation before removal. Use when removing outdated information, incorrect memories, sensitive data, or cleaning up after experiments. +--- + +# Forget + +Delete specific memories from Mem0. + +## Execution + +### Step 1: Parse input + +The user provides either: +- A search query: `/mem0-forget travel plans` +- A memory ID: `/mem0-forget ` + +If no argument, ask: "What should I forget? Provide a search query or memory ID." + +### Step 2: Find memories + +**If memory ID provided** (looks like a UUID or hex string): +- Use `mem0_memory` tool with `action="search"` and the ID as query, or look it up directly. +- Show: `Found: "" (created )` + +**If search query provided:** +- Use `mem0_memory` tool with `action="search"`, `query=`. +- Show numbered list: + ``` + Found memories matching "": + 1. [] [ID: ] + 2. ... + ``` + +### Step 3: Confirm + +Ask: "Delete which memories? Enter numbers (e.g., 1,3,5), 'all', or 'cancel'." + +For a single memory ID, ask: "Delete this memory? [y/N]" + +**Never delete without confirmation.** This is destructive. + +### Step 4: Delete + +For each confirmed memory, use `mem0_memory` tool with `action="delete"` and the memory ID. + +### Step 5: Report + +``` +Deleted memories. +``` + +If any deletions failed, report which ones and why. diff --git a/pi-agent-plugin/skills/pin/SKILL.md b/pi-agent-plugin/skills/pin/SKILL.md new file mode 100644 index 000000000..11b075d37 --- /dev/null +++ b/pi-agent-plugin/skills/pin/SKILL.md @@ -0,0 +1,48 @@ +--- +name: pin +description: Pins or unpins a memory to protect it from pruning during dream consolidation. Use when a memory is critical and must never be removed, such as core preferences, important decisions, or immutable personal facts. +--- + +# Pin + +Pin a memory to mark it as high-priority and protect from dream pruning. + +## Execution + +### Step 1: Find the memory + +The user provides either a search query or memory ID. + +**If memory ID:** Look it up directly. + +**If search query:** +- Use `mem0_memory` tool with `action="search"`, `query=`. +- Show numbered list with content previews. +- Ask: "Which memory to pin? Enter a number." + +### Step 2: Pin it + +Pinning works by prepending `[PINNED]` to the memory text. This marker tells the dream consolidation to skip it during pruning. + +Use `mem0_memory` tool with `action="add"`, `content="[PINNED] "`. + +Then delete the original using `mem0_memory` with `action="delete"` and the original memory ID. + +**For new memories** (user wants to pin text that isn't stored yet): +- Use `mem0_memory` tool with `action="add"`, `content="[PINNED] "`. + +### Step 3: Confirm + +``` +Pinned: "" +``` + +Append `...` only if content exceeds 80 characters. + +### Unpin + +If the user says "unpin": +1. Find the memory (search or by ID). +2. Create a new memory without the `[PINNED]` prefix. +3. Delete the pinned version. +4. Print: `Unpinned: "..."` diff --git a/pi-agent-plugin/skills/remember/SKILL.md b/pi-agent-plugin/skills/remember/SKILL.md new file mode 100644 index 000000000..4b7456b18 --- /dev/null +++ b/pi-agent-plugin/skills/remember/SKILL.md @@ -0,0 +1,50 @@ +--- +name: remember +description: Stores a memory verbatim from user input with appropriate category classification. Use when the user says remember this, save this, store this, note that, or explicitly asks to record a preference, decision, goal, or lesson. +--- + +# Remember + +Store a fact, preference, or learning directly into Mem0. + +## Execution + +### Step 1: Extract the content + +The user provides the content as an argument: `/mem0-remember ` + +If no text was provided, ask: "What should I remember?" + +### Step 2: Classify the memory + +Based on the content, pick the best category: + +| Content signal | Category | +|---|---| +| "I prefer...", "I like...", "use X instead of Y" | `preferences` | +| "we decided...", "always use...", "never..." | `decisions` | +| "I learned...", "figured out...", "don't try..." | `lessons` | +| "my goal is...", "I want to...", "working toward..." | `goals` | +| "I work at...", "my role is...", "my team..." | `work` | +| "every day I...", "my workflow is..." | `routines` | +| "I'm working on...", "the project involves..." | `projects` | +| "John is...", "my manager...", "the team..." | `relationships` | +| "my name is...", "I'm from...", "I studied..." | `identity` | +| setup, tools, config, environment | `technical` | +| anything else | `lessons` | + +### Step 3: Store + +Use the `mem0_memory` tool with: +- `action="add"` +- `content=""` + +The `/mem0-remember` command stores verbatim — no inference. This is already handled by the command. + +### Step 4: Confirm + +``` +Remembered as : "" +``` + +Append `...` only if content was truncated (longer than 80 chars). diff --git a/pi-agent-plugin/skills/search/SKILL.md b/pi-agent-plugin/skills/search/SKILL.md new file mode 100644 index 000000000..a53ce7764 --- /dev/null +++ b/pi-agent-plugin/skills/search/SKILL.md @@ -0,0 +1,41 @@ +--- +name: search +description: Searches memories and displays compact one-liner results, or looks up a specific memory by ID. Use for quick memory lookups, checking if something was recorded, resolving [mem0:id] citations, or browsing memories without full category detail. +--- + +# Search / Peek + +Quick semantic search with compact output. Lighter than `/mem0-tour`. + +## Execution + +### Step 1: Parse query + +The user provides a search query: `/mem0-search favorite restaurants` + +If no query provided, ask: "What should I search for?" + +**Memory ID detection:** If the query matches a UUID pattern (`^[a-f0-9-]{20,}$`), treat it as a direct memory lookup instead of a search. + +### Step 2: Search + +Use `mem0_memory` tool with `action="search"`, `query=`. + +### Step 3: Display + +Show compact results: + +``` +## mem0 search: "" ( results) + +1. [preferences] Prefers window seats on flights (2026-05-15) [mem0:a3f8b2c1] +2. [goals] Wants to visit Japan in 2027 (2026-05-10) [mem0:7e2d9f4a] +3. [identity] Lives in San Francisco (2026-05-08) [mem0:c4d5e6f7] +``` + +Format: `. [] () [mem0:]` + +If no results: +``` +No memories matching "". +``` diff --git a/pi-agent-plugin/skills/status/SKILL.md b/pi-agent-plugin/skills/status/SKILL.md new file mode 100644 index 000000000..75d073fd7 --- /dev/null +++ b/pi-agent-plugin/skills/status/SKILL.md @@ -0,0 +1,89 @@ +--- +name: status +description: Diagnoses Mem0 connectivity, API key validity, and memory read/write functionality. Use when memory operations fail, searches return empty, or to verify the plugin is working correctly. +--- + +# Health Check / Status + +Run a diagnostic check on the Mem0 plugin. Useful for troubleshooting. + +## Execution + +Run ALL checks, then display a single summary. Do not stop on the first failure. + +### Check 1: API key + +Verify the API key is configured. The plugin loads it from `MEM0_API_KEY` env var or `~/.pi/agent/mem0-config.json`. + +- If not set: FAIL — "No API key configured" +- If set: PASS — show first 6 chars followed by `...` + +### Check 2: Identity resolution + +Report the resolved identity: +- `user_id`: from config, env, or system user +- `project_id`: auto-detected from current directory +- `session_id`: current session identifier + +PASS if user_id and project_id are non-empty. WARN if any falls back to defaults. + +### Check 3: Connectivity + +Use `mem0_memory` tool with `action="search"`, `query="health check"`. + +- If returns successfully (even empty): PASS +- If errors: FAIL — show the error message + +### Check 4: Memory write capability + +Use `mem0_memory` tool with `action="add"`, `content="Health check probe — safe to delete."`. + +- If succeeds: PASS — then clean up by deleting the probe memory. +- If errors: FAIL — show the error. + +### Display + +``` +## mem0 health + +PASS API Key m0-dVe... +PASS Identity user=kartik, project=my-app, session=abc123 +PASS Connectivity 142ms +PASS Write/Read write + delete OK + +All checks passed. +``` + +If any check fails, add a `## Troubleshooting` section with specific fix steps. + +## Extended mode: Memory Quality Analysis + +When invoked with `--deep` (e.g., `/mem0-status --deep`), run the standard checks above **plus** a memory quality scan. + +### Quality Check 1: Duplicates + +Fetch all memories with `mem0_memory` `action="get_all"`. Compare pairs within the same category for high textual overlap (shared nouns > 60%). Report: + +``` +Potential duplicates: pairs + [mem0:] ~ [mem0:] — both about "" +``` + +### Quality Check 2: Stale memories + +Flag memories older than 180 days that haven't been accessed recently. + +### Quality Check 3: Contradictions + +Within each category, flag pairs that assert opposing facts. + +### Quality summary + +``` +## Memory Quality + +Duplicates: · Stale: · Contradictions: +``` + +If all counts are 0: `Memory quality: clean.` +If any non-zero: append `Run /mem0-dream to fix.` diff --git a/pi-agent-plugin/skills/tour/SKILL.md b/pi-agent-plugin/skills/tour/SKILL.md new file mode 100644 index 000000000..b635b46ac --- /dev/null +++ b/pi-agent-plugin/skills/tour/SKILL.md @@ -0,0 +1,88 @@ +--- +name: tour +description: Browses all stored memories grouped by category with full content display. Use when reviewing all memories, exploring stored knowledge, onboarding to a new session, or getting an overview of what the agent remembers. +--- + +# Memory Tour + +Show the user what Mem0 has stored — a full walkthrough of all memories grouped by category. + +## Cross-project mode + +When invoked with `--all-projects` (e.g., `/mem0-tour --all-projects`), search across ALL projects: + +1. Use `mem0_memory` tool with `action="get_all"`, `scope="global"` — no project filter. +2. Group results by project first, then by category within each project. +3. Display: + ``` + ## ( memories) <- current + **Goals** — + ... + + ## ( memories) + ... + + memories across projects + ``` +4. Mark the current project with `<- current` in the heading. + +If `--all-projects` is NOT present, use the standard single-project flow below. + +## Search mode + +When `/mem0-tour` receives a search query argument (e.g., `/mem0-tour cooking recipes`), run in **search mode** — compact one-liner results: + +1. Use `mem0_memory` tool with `action="search"`, `query=`. +2. Display compact results (same format as the search skill). +3. If no results: `No memories matching "".` + +If no query argument and no `--all-projects` flag, use the full tour flow below. + +## Execution + +### Step 1: Fetch ALL memories + +Use `mem0_memory` tool with `action="get_all"`. + +### Step 2: Group by category + +Group memories using their `categories` field. Map to display names: + +| Category | Display name | +|---|---| +| `identity` | Identity & Background | +| `preferences` | Preferences | +| `goals` | Goals & Aspirations | +| `projects` | Projects & Initiatives | +| `decisions` | Decisions | +| `technical` | Technical Knowledge | +| `relationships` | People & Relationships | +| `routines` | Routines & Workflows | +| `lessons` | Lessons Learned | +| `work` | Work & Professional | +| anything else | Other | + +### Step 3: Display results + +Sort groups by descending memory count. For each group: + +``` +## ( memories) +- () +- ... +``` + +Show the **full memory text** for each entry — do NOT truncate. If a group has more than 10 entries, show top 10 by recency and note `... and more`. + +### Step 4: Print totals + +``` + memories across categories +``` + +### Step 5: Empty state + +If zero memories found: +``` +No memories stored yet. Start a conversation — Mem0 captures learnings automatically, or use /mem0-remember to store something manually. +``` diff --git a/pi-agent-plugin/src/capture/index.ts b/pi-agent-plugin/src/capture/index.ts new file mode 100644 index 000000000..3b7a5d5d4 --- /dev/null +++ b/pi-agent-plugin/src/capture/index.ts @@ -0,0 +1,70 @@ +import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; +import type MemoryClient from "mem0ai"; +import type { Mem0Config, ScopeContext } from "../types.ts"; +import { DEFAULT_CUSTOM_CATEGORIES } from "../types.ts"; +import { resolveAddParams } from "../memory/scoping.ts"; +import { captureEvent } from "../telemetry.ts"; + +interface MessageLike { + role: string; + content?: unknown; +} + +function extractText(content: unknown): string | null { + if (typeof content === "string") return content; + if (Array.isArray(content)) { + const texts = content + .filter((b: any) => b.type === "text" && typeof b.text === "string") + .map((b: any) => b.text); + return texts.length > 0 ? texts.join("\n") : null; + } + return null; +} + +export function extractConversation( + messages: MessageLike[], +): Array<{ role: "user" | "assistant"; content: string }> { + const result: Array<{ role: "user" | "assistant"; content: string }> = []; + + for (const msg of messages) { + if (msg.role !== "user" && msg.role !== "assistant") continue; + const text = extractText(msg.content); + if (!text) continue; + result.push({ role: msg.role as "user" | "assistant", content: text }); + } + + return result; +} + +export function setupAutoCapture( + pi: ExtensionAPI, + mem0: MemoryClient, + config: Mem0Config, + getScopeCtx: () => ScopeContext, + telemetryCtx?: { apiKey?: string }, +): void { + if (!config.autoCapture) return; + + pi.on("agent_end", async (event) => { + const messages = event.messages ?? []; + const conversation = extractConversation(messages); + if (conversation.length === 0) return; + + const scopeCtx = getScopeCtx(); + const addParams = resolveAddParams("project", scopeCtx); + + try { + await mem0.add(conversation, { + ...addParams, + customCategories: DEFAULT_CUSTOM_CATEGORIES, + }); + captureEvent("pi.capture.auto", { success: true, message_count: conversation.length }, telemetryCtx); + } catch (err: unknown) { + captureEvent("pi.capture.auto", { + success: false, + error_type: err instanceof Error ? err.name : "unknown", + }, telemetryCtx); + console.error("[mem0] auto-capture failed:", err); + } + }); +} diff --git a/pi-agent-plugin/src/commands.test.ts b/pi-agent-plugin/src/commands.test.ts new file mode 100644 index 000000000..ac51ac964 --- /dev/null +++ b/pi-agent-plugin/src/commands.test.ts @@ -0,0 +1,297 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { registerCommands } from "./commands.ts"; +import type { Mem0Config, ScopeContext } from "./types.ts"; + +vi.mock("./telemetry.ts", () => ({ + captureCommandEvent: vi.fn(), +})); + +vi.mock("./dream/index.ts", () => ({ + acquireDreamLock: vi.fn(() => true), +})); + +vi.mock("./dream/prompt.ts", () => ({ + DREAM_PROTOCOL: "dream protocol text", +})); + +function makeMem0() { + return { + search: vi.fn(), + delete: vi.fn(), + add: vi.fn(), + get: vi.fn(), + getAll: vi.fn(), + update: vi.fn(), + } as any; +} + +function makePi() { + const commands = new Map Promise }>(); + return { + registerCommand: vi.fn((name: string, opts: any) => { + commands.set(name, opts); + }), + sendMessage: vi.fn(), + _commands: commands, + _invoke: (name: string, args: string, ctx: any) => commands.get(name)!.handler(args, ctx), + }; +} + +function makeCtx(confirmResult = true) { + return { + hasUI: true, + ui: { + notify: vi.fn(), + confirm: vi.fn(async () => confirmResult), + select: vi.fn(), + input: vi.fn(), + }, + }; +} + +const defaultConfig: Mem0Config = { + apiKey: "test-key", + userId: "test-user", + autoCapture: false, + defaultScope: "project", + contextInjection: false, + dream: { enabled: false, auto: false, minHours: 24, minSessions: 5, minMemories: 20 }, +}; + +const scopeCtx: ScopeContext = { userId: "test-user", appId: "test-app", runId: "test-run" }; + +describe("registerCommands", () => { + let pi: ReturnType; + let mem0: ReturnType; + + beforeEach(() => { + pi = makePi(); + mem0 = makeMem0(); + registerCommands(pi as any, mem0, defaultConfig, () => scopeCtx); + }); + + it("registers all expected commands", () => { + const names = [...pi._commands.keys()]; + expect(names).toContain("mem0-remember"); + expect(names).toContain("mem0-forget"); + expect(names).toContain("mem0-search"); + expect(names).toContain("mem0-tour"); + expect(names).toContain("mem0-dream"); + expect(names).toContain("mem0-pin"); + expect(names).toContain("mem0-scope"); + expect(names).toContain("mem0-status"); + }); + + describe("/mem0-forget", () => { + it("shows warning when no query provided", async () => { + const ctx = makeCtx(); + await pi._invoke("mem0-forget", "", ctx); + expect(ctx.ui.notify).toHaveBeenCalledWith("Usage: /mem0-forget ", "warning"); + expect(mem0.search).not.toHaveBeenCalled(); + }); + + it("notifies when no memories match", async () => { + const ctx = makeCtx(); + mem0.search.mockResolvedValue({ results: [] }); + await pi._invoke("mem0-forget", "old preference", ctx); + expect(ctx.ui.notify).toHaveBeenCalledWith("No matching memories found.", "info"); + }); + + it("asks for confirmation before deleting a single match", async () => { + const ctx = makeCtx(true); + mem0.search.mockResolvedValue({ results: [{ id: "abc-123", memory: "test mem" }] }); + mem0.delete.mockResolvedValue({ message: "Deleted" }); + + await pi._invoke("mem0-forget", "test", ctx); + + expect(ctx.ui.confirm).toHaveBeenCalledWith( + "Delete this memory?", + expect.stringContaining("test mem"), + ); + expect(mem0.delete).toHaveBeenCalledWith("abc-123"); + }); + + it("does not delete when user cancels confirmation", async () => { + const ctx = makeCtx(false); + mem0.search.mockResolvedValue({ results: [{ id: "abc-123", memory: "test mem" }] }); + + await pi._invoke("mem0-forget", "test", ctx); + + expect(ctx.ui.confirm).toHaveBeenCalled(); + expect(mem0.delete).not.toHaveBeenCalled(); + expect(ctx.ui.notify).toHaveBeenCalledWith("Cancelled.", "info"); + }); + + it("uses select UI for multiple matches and deletes chosen memory", async () => { + const ctx = makeCtx(); + mem0.search.mockResolvedValue({ + results: [ + { id: "id-1", memory: "mem one" }, + { id: "id-2", memory: "mem two" }, + ], + }); + mem0.delete.mockResolvedValue({ message: "Deleted" }); + ctx.ui.select = vi.fn(async (_title: string, options: string[]) => options[1]); + + await pi._invoke("mem0-forget", "test", ctx); + + expect(ctx.ui.select).toHaveBeenCalledWith( + "Which memory should I delete?", + expect.arrayContaining([ + expect.stringContaining("mem one"), + expect.stringContaining("mem two"), + ]), + ); + expect(mem0.delete).toHaveBeenCalledWith("id-2"); + }); + + it("does not delete when user cancels select", async () => { + const ctx = makeCtx(); + ctx.ui.select = vi.fn(async () => undefined); + mem0.search.mockResolvedValue({ + results: [ + { id: "id-1", memory: "mem one" }, + { id: "id-2", memory: "mem two" }, + ], + }); + + await pi._invoke("mem0-forget", "test", ctx); + + expect(mem0.delete).not.toHaveBeenCalled(); + expect(ctx.ui.notify).toHaveBeenCalledWith("Cancelled.", "info"); + }); + }); + + describe("/mem0-pin", () => { + it("uses update to pin in-place, preserving memory ID", async () => { + const ctx = makeCtx(true); + mem0.search.mockResolvedValue({ results: [{ id: "abc-123", memory: "important fact" }] }); + mem0.update.mockResolvedValue([]); + + await pi._invoke("mem0-pin", "important", ctx); + + expect(ctx.ui.confirm).toHaveBeenCalledWith( + "Pin this memory?", + expect.stringContaining("important fact"), + ); + expect(mem0.update).toHaveBeenCalledWith("abc-123", { text: "[PINNED] important fact" }); + expect(mem0.add).not.toHaveBeenCalled(); + expect(mem0.delete).not.toHaveBeenCalled(); + }); + + it("does not pin when user cancels", async () => { + const ctx = makeCtx(false); + mem0.search.mockResolvedValue({ results: [{ id: "abc-123", memory: "fact" }] }); + + await pi._invoke("mem0-pin", "fact", ctx); + + expect(mem0.update).not.toHaveBeenCalled(); + }); + + it("skips already-pinned memories", async () => { + const ctx = makeCtx(); + mem0.search.mockResolvedValue({ results: [{ id: "abc-123", memory: "[PINNED] fact" }] }); + + await pi._invoke("mem0-pin", "fact", ctx); + + expect(ctx.ui.confirm).not.toHaveBeenCalled(); + expect(mem0.add).not.toHaveBeenCalled(); + expect(ctx.ui.notify).toHaveBeenCalledWith("Already pinned.", "info"); + }); + + it("uses select UI for multiple matches and pins chosen memory", async () => { + const ctx = makeCtx(); + mem0.search.mockResolvedValue({ + results: [ + { id: "id-1", memory: "fact one" }, + { id: "id-2", memory: "fact two" }, + ], + }); + mem0.update.mockResolvedValue([]); + ctx.ui.select = vi.fn(async (_title: string, options: string[]) => options[1]); + + await pi._invoke("mem0-pin", "fact", ctx); + + expect(ctx.ui.select).toHaveBeenCalledWith( + "Which memory should I pin?", + expect.arrayContaining([ + expect.stringContaining("fact one"), + expect.stringContaining("fact two"), + ]), + ); + expect(mem0.update).toHaveBeenCalledWith("id-2", { text: "[PINNED] fact two" }); + }); + + it("does not pin when user cancels select", async () => { + const ctx = makeCtx(); + ctx.ui.select = vi.fn(async () => undefined); + mem0.search.mockResolvedValue({ + results: [ + { id: "id-1", memory: "fact one" }, + { id: "id-2", memory: "fact two" }, + ], + }); + + await pi._invoke("mem0-pin", "fact", ctx); + + expect(mem0.update).not.toHaveBeenCalled(); + expect(ctx.ui.notify).toHaveBeenCalledWith("Cancelled.", "info"); + }); + }); + + describe("/mem0-search", () => { + it("always performs semantic search", async () => { + const ctx = makeCtx(); + mem0.search.mockResolvedValue({ results: [{ id: "id-1", memory: "result" }] }); + + await pi._invoke("mem0-search", "my preferences", ctx); + + expect(mem0.search).toHaveBeenCalledWith("my preferences", expect.any(Object)); + expect(pi.sendMessage).toHaveBeenCalledWith( + expect.objectContaining({ customType: "mem0-search" }), + ); + }); + + it("uses semantic search even for hex-looking strings", async () => { + const ctx = makeCtx(); + mem0.search.mockResolvedValue({ results: [] }); + + await pi._invoke("mem0-search", "abcd1234", ctx); + + expect(mem0.search).toHaveBeenCalledWith("abcd1234", expect.any(Object)); + expect(mem0.getAll).not.toHaveBeenCalled(); + expect(mem0.get).not.toHaveBeenCalled(); + }); + + it("shows empty results message", async () => { + const ctx = makeCtx(); + mem0.search.mockResolvedValue({ results: [] }); + + await pi._invoke("mem0-search", "nonexistent", ctx); + + expect(pi.sendMessage).toHaveBeenCalledWith( + expect.objectContaining({ content: "No memories found." }), + ); + }); + }); + + describe("/mem0-remember", () => { + it("stores a memory verbatim", async () => { + const ctx = makeCtx(); + mem0.add.mockResolvedValue({ message: "Memory stored." }); + + await pi._invoke("mem0-remember", "I prefer dark mode", ctx); + + expect(mem0.add).toHaveBeenCalledWith( + [{ role: "user", content: "I prefer dark mode" }], + expect.objectContaining({ infer: false }), + ); + }); + + it("shows warning when no text provided", async () => { + const ctx = makeCtx(); + await pi._invoke("mem0-remember", " ", ctx); + expect(ctx.ui.notify).toHaveBeenCalledWith("Usage: /mem0-remember ", "warning"); + }); + }); +}); diff --git a/pi-agent-plugin/src/commands.ts b/pi-agent-plugin/src/commands.ts new file mode 100644 index 000000000..196ac0ebf --- /dev/null +++ b/pi-agent-plugin/src/commands.ts @@ -0,0 +1,291 @@ +import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; +import type MemoryClient from "mem0ai"; +import type { Mem0Config, ScopeContext, Scope } from "./types.ts"; +import { DEFAULT_CUSTOM_CATEGORIES } from "./types.ts"; +import { resolveSearchFilters, resolveAddParams } from "./memory/scoping.ts"; +import { formatMemoryList, formatMemoryCompact, groupByCategory } from "./memory/formatting.ts"; +import { DREAM_PROTOCOL } from "./dream/prompt.ts"; +import { acquireDreamLock } from "./dream/index.ts"; +import { CONFIG_DIR } from "./config/index.ts"; +import { captureCommandEvent } from "./telemetry.ts"; + +export function registerCommands( + pi: ExtensionAPI, + mem0: MemoryClient, + config: Mem0Config, + getScopeCtx: () => ScopeContext, + telemetryCtx?: { apiKey?: string }, +): void { + // ── /mem0-remember ────────────────────────────────────────────────── + pi.registerCommand("mem0-remember", { + description: "Store a memory verbatim (no inference)", + handler: async (args, ctx) => { + const text = args?.trim(); + if (!text) { + ctx.ui.notify("Usage: /mem0-remember ", "warning"); + return; + } + + const scopeCtx = getScopeCtx(); + const addParams = resolveAddParams(config.defaultScope, scopeCtx); + const result = await mem0.add( + [{ role: "user", content: text }], + { ...addParams, customCategories: DEFAULT_CUSTOM_CATEGORIES, infer: false }, + ); + const msg = (result as { message?: string }).message ?? "Memory stored."; + captureCommandEvent("mem0-remember", {}, telemetryCtx); + ctx.ui.notify(msg, "info"); + }, + }); + + // ── /mem0-forget ──────────────────────────────────────────────────── + pi.registerCommand("mem0-forget", { + description: "Delete memories matching a natural language query", + handler: async (args, ctx) => { + const query = args?.trim(); + if (!query) { + ctx.ui.notify("Usage: /mem0-forget ", "warning"); + return; + } + + const scopeCtx = getScopeCtx(); + const filters = resolveSearchFilters(config.defaultScope, scopeCtx); + const result = await mem0.search(query, { filters }); + const memories = result.results ?? []; + + if (memories.length === 0) { + captureCommandEvent("mem0-forget", { result_count: 0 }, telemetryCtx); + ctx.ui.notify("No matching memories found.", "info"); + return; + } + + if (memories.length === 1) { + const target = memories[0]; + const confirmed = await ctx.ui.confirm( + "Delete this memory?", + formatMemoryCompact(target), + ); + if (!confirmed) { + ctx.ui.notify("Cancelled.", "info"); + return; + } + await mem0.delete(target.id); + captureCommandEvent("mem0-forget", { deleted_count: 1 }, telemetryCtx); + ctx.ui.notify(`Deleted: ${formatMemoryCompact(target)}`, "info"); + return; + } + + const labels = memories.map((m) => formatMemoryCompact(m)); + const selected = await ctx.ui.select("Which memory should I delete?", labels); + if (!selected) { + ctx.ui.notify("Cancelled.", "info"); + return; + } + const idx = labels.indexOf(selected); + if (idx < 0) return; + const target = memories[idx]; + await mem0.delete(target.id); + captureCommandEvent("mem0-forget", { deleted_count: 1 }, telemetryCtx); + ctx.ui.notify(`Deleted: ${formatMemoryCompact(target)}`, "info"); + }, + }); + + // ── /mem0-search ──────────────────────────────────────────────────── + pi.registerCommand("mem0-search", { + description: "Semantic search across memories", + handler: async (args, ctx) => { + const query = args?.trim(); + if (!query) { + ctx.ui.notify("Usage: /mem0-search ", "warning"); + return; + } + + const scopeCtx = getScopeCtx(); + const filters = resolveSearchFilters(config.defaultScope, scopeCtx); + const result = await mem0.search(query, { filters }); + const memories = result.results ?? []; + + captureCommandEvent("mem0-search", { result_count: memories.length }, telemetryCtx); + pi.sendMessage({ + customType: "mem0-search", + content: formatMemoryList(memories), + display: true, + }); + }, + }); + + // ── /mem0-tour ────────────────────────────────────────────────────── + pi.registerCommand("mem0-tour", { + description: "Browse all memories grouped by category", + handler: async (args, ctx) => { + const raw = args?.trim().toLowerCase(); + const validScopes: Scope[] = ["project", "session", "global"]; + if (raw && !validScopes.includes(raw as Scope)) { + ctx.ui.notify(`Invalid scope "${raw}". Must be one of: ${validScopes.join(", ")}`, "warning"); + return; + } + const scope: Scope = (raw as Scope) || config.defaultScope; + const scopeCtx = getScopeCtx(); + const filters = resolveSearchFilters(scope, scopeCtx); + const result = await mem0.getAll({ filters }); + const memories = result.results ?? []; + + if (memories.length === 0) { + captureCommandEvent("mem0-tour", { memory_count: 0, scope }, telemetryCtx); + pi.sendMessage({ customType: "mem0-tour", content: "No memories found.", display: true }); + return; + } + + const groups = groupByCategory(memories); + const lines: string[] = [`**Memory Tour** (${memories.length} total, scope: ${scope})`, ""]; + + for (const [category, items] of groups) { + lines.push(`### ${category} (${items.length})`); + for (const m of items) { + lines.push(`- ${formatMemoryCompact(m)}`); + } + lines.push(""); + } + + captureCommandEvent("mem0-tour", { memory_count: memories.length, scope }, telemetryCtx); + pi.sendMessage({ customType: "mem0-tour", content: lines.join("\n"), display: true }); + }, + }); + + // ── /mem0-dream ───────────────────────────────────────────────────── + pi.registerCommand("mem0-dream", { + description: "Consolidate memories — merge duplicates, prune stale entries, resolve contradictions", + handler: async (_args, ctx) => { + if (!acquireDreamLock(CONFIG_DIR)) { + ctx.ui.notify("A dream consolidation is already in progress.", "warning"); + return; + } + + captureCommandEvent("mem0-dream", {}, telemetryCtx); + pi.sendMessage({ customType: "mem0-dream", content: DREAM_PROTOCOL, display: true }, { triggerTurn: true }); + ctx.ui.notify("Dream consolidation started.", "info"); + }, + }); + + // ── /mem0-pin ─────────────────────────────────────────────────────── + pi.registerCommand("mem0-pin", { + description: "Pin a memory to protect it from dream pruning", + handler: async (args, ctx) => { + const query = args?.trim(); + if (!query) { + ctx.ui.notify("Usage: /mem0-pin ", "warning"); + return; + } + + const scopeCtx = getScopeCtx(); + const filters = resolveSearchFilters(config.defaultScope, scopeCtx); + const result = await mem0.search(query, { filters }); + const memories = result.results ?? []; + + if (memories.length === 0) { + captureCommandEvent("mem0-pin", { result_count: 0 }, telemetryCtx); + ctx.ui.notify("No matching memories found to pin.", "info"); + return; + } + + if (memories.length === 1) { + const target = memories[0]; + const text = target.memory ?? ""; + if (text.startsWith("[PINNED]")) { + ctx.ui.notify("Already pinned.", "info"); + return; + } + const confirmed = await ctx.ui.confirm( + "Pin this memory?", + formatMemoryCompact(target), + ); + if (!confirmed) { + ctx.ui.notify("Cancelled.", "info"); + return; + } + await mem0.update(target.id, { text: `[PINNED] ${text}` }); + captureCommandEvent("mem0-pin", { pinned: true }, telemetryCtx); + ctx.ui.notify(`Pinned: ${formatMemoryCompact(target)}`, "info"); + return; + } + + const labels = memories.map((m) => formatMemoryCompact(m)); + const selected = await ctx.ui.select("Which memory should I pin?", labels); + if (!selected) { + ctx.ui.notify("Cancelled.", "info"); + return; + } + const idx = labels.indexOf(selected); + if (idx < 0) return; + const target = memories[idx]; + const selectedText = target.memory ?? ""; + if (selectedText.startsWith("[PINNED]")) { + ctx.ui.notify("Already pinned.", "info"); + return; + } + await mem0.update(target.id, { text: `[PINNED] ${selectedText}` }); + captureCommandEvent("mem0-pin", { pinned: true }, telemetryCtx); + ctx.ui.notify(`Pinned: ${formatMemoryCompact(target)}`, "info"); + }, + }); + + // ── /mem0-scope ───────────────────────────────────────────────────── + pi.registerCommand("mem0-scope", { + description: "Change default memory scope for this session (project, session, global)", + handler: async (args, ctx) => { + const scope = args?.trim().toLowerCase(); + const valid: Scope[] = ["project", "session", "global"]; + + if (!scope) { + ctx.ui.notify(`Current scope: ${config.defaultScope}. Usage: /mem0-scope <${valid.join("|")}>`, "info"); + return; + } + + if (!valid.includes(scope as Scope)) { + ctx.ui.notify(`Invalid scope "${scope}". Must be one of: ${valid.join(", ")}`, "warning"); + return; + } + + config.defaultScope = scope as Scope; + captureCommandEvent("mem0-scope", { scope }, telemetryCtx); + ctx.ui.notify(`Default scope changed to "${scope}" for this session.`, "info"); + }, + }); + + // ── /mem0-status ──────────────────────────────────────────────────── + pi.registerCommand("mem0-status", { + description: "Show connection health, identity, project, and memory count", + handler: async (_args, _ctx) => { + const scopeCtx = getScopeCtx(); + const filters = resolveSearchFilters("project", scopeCtx); + + let count = 0; + let connected = false; + try { + const result = await mem0.getAll({ filters }); + count = result.count ?? (result.results ?? []).length; + connected = true; + } catch { + connected = false; + } + + const lines = [ + "**Mem0 Status**", + "", + `- Connection: ${connected ? "connected" : "disconnected"}`, + `- User: ${scopeCtx.userId}`, + `- Project: ${scopeCtx.appId}`, + `- Session: ${scopeCtx.runId}`, + `- Default scope: ${config.defaultScope}`, + `- Project memories: ${count}`, + `- Auto-capture: ${config.autoCapture ? "on" : "off"}`, + `- Dream: ${config.dream.enabled ? "enabled" : "disabled"}`, + ]; + + captureCommandEvent("mem0-status", { connected, memory_count: count }, telemetryCtx); + pi.sendMessage({ customType: "mem0-status", content: lines.join("\n"), display: true }); + }, + }); + + +} diff --git a/pi-agent-plugin/src/config/index.ts b/pi-agent-plugin/src/config/index.ts new file mode 100644 index 000000000..d01a412fa --- /dev/null +++ b/pi-agent-plugin/src/config/index.ts @@ -0,0 +1,58 @@ +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import type { Mem0Config, DreamConfig } from "../types.ts"; + +const AGENT_ROOT = path.join(os.homedir(), ".pi", "agent"); +export const CONFIG_DIR = AGENT_ROOT; +const CONFIG_PATH = path.join(AGENT_ROOT, "mem0-config.json"); + +const DEFAULT_DREAM: DreamConfig = { + enabled: true, + auto: true, + minHours: 24, + minSessions: 5, + minMemories: 20, +}; + +const DEFAULT_CONFIG: Mem0Config = { + apiKey: "", + userId: "", + autoCapture: true, + defaultScope: "project", + contextInjection: false, + dream: DEFAULT_DREAM, +}; + +export function loadConfig(): Mem0Config { + let fileConfig: Partial = {}; + + if (fs.existsSync(CONFIG_PATH)) { + try { + const raw = fs.readFileSync(CONFIG_PATH, "utf-8"); + fileConfig = JSON.parse(raw); + } catch { + // Corrupted config — use defaults + } + } + + const dream: DreamConfig = { + ...DEFAULT_DREAM, + ...(fileConfig.dream ?? {}), + }; + + const config: Mem0Config = { + ...DEFAULT_CONFIG, + ...fileConfig, + dream, + }; + + if (process.env.MEM0_API_KEY) { + config.apiKey = process.env.MEM0_API_KEY; + } + if (process.env.MEM0_USER_ID) { + config.userId = process.env.MEM0_USER_ID; + } + + return config; +} diff --git a/pi-agent-plugin/src/dream/index.ts b/pi-agent-plugin/src/dream/index.ts new file mode 100644 index 000000000..2129d947b --- /dev/null +++ b/pi-agent-plugin/src/dream/index.ts @@ -0,0 +1,115 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; +import type { DreamState, DreamLock, DreamConfig } from "../types.ts"; + +const LOCK_STALE_MS = 60 * 60 * 1000; + +const DEFAULTS: DreamConfig = { + enabled: true, + auto: true, + minHours: 24, + minSessions: 5, + minMemories: 20, +}; + +function statePath(stateDir: string): string { + return path.join(stateDir, "mem0-dream-state.json"); +} + +function lockPath(stateDir: string): string { + return path.join(stateDir, "mem0-dream.lock"); +} + +function ensureDir(dir: string): void { + try { + fs.mkdirSync(dir, { recursive: true }); + } catch { /* exists */ } +} + +function readState(stateDir: string): DreamState { + try { + const raw = fs.readFileSync(statePath(stateDir), "utf-8"); + return JSON.parse(raw) as DreamState; + } catch { + return { lastConsolidatedAt: 0, sessionsSince: 0, lastSessionId: null }; + } +} + +function writeState(stateDir: string, state: DreamState): void { + ensureDir(stateDir); + fs.writeFileSync(statePath(stateDir), JSON.stringify(state, null, 2)); +} + +export function incrementSessionCount(stateDir: string, sessionId: string): void { + const state = readState(stateDir); + if (state.lastSessionId !== sessionId) { + state.sessionsSince++; + state.lastSessionId = sessionId; + writeState(stateDir, state); + } +} + +export function checkCheapGates( + stateDir: string, + config: Partial, +): { proceed: boolean; reason?: string } { + const minHours = config.minHours ?? DEFAULTS.minHours; + const minSessions = config.minSessions ?? DEFAULTS.minSessions; + const state = readState(stateDir); + + const hoursSince = (Date.now() - state.lastConsolidatedAt) / 3_600_000; + if (hoursSince < minHours) { + return { proceed: false, reason: `time: ${hoursSince.toFixed(1)}h < ${minHours}h` }; + } + + if (state.sessionsSince < minSessions) { + return { proceed: false, reason: `sessions: ${state.sessionsSince} < ${minSessions}` }; + } + + return { proceed: true }; +} + +export function checkMemoryGate( + memoryCount: number, + config: Partial, +): { pass: boolean; reason?: string } { + const minMemories = config.minMemories ?? DEFAULTS.minMemories; + if (memoryCount < minMemories) { + return { pass: false, reason: `memories: ${memoryCount} < ${minMemories}` }; + } + return { pass: true }; +} + +export function acquireDreamLock(stateDir: string): boolean { + ensureDir(stateDir); + const lp = lockPath(stateDir); + + try { + const raw = fs.readFileSync(lp, "utf-8"); + const lock = JSON.parse(raw) as DreamLock; + if (Date.now() - lock.startedAt < LOCK_STALE_MS) { + return false; + } + try { fs.unlinkSync(lp); } catch { /* race ok */ } + } catch { /* no lock file */ } + + const lock: DreamLock = { pid: process.pid, startedAt: Date.now() }; + try { + fs.writeFileSync(lp, JSON.stringify(lock), { flag: "wx" }); + return true; + } catch { + return false; + } +} + +export function releaseDreamLock(stateDir: string): void { + try { fs.unlinkSync(lockPath(stateDir)); } catch { /* already gone */ } +} + +export function recordDreamCompletion(stateDir: string): void { + const state = readState(stateDir); + state.lastConsolidatedAt = Date.now(); + state.sessionsSince = 0; + state.lastSessionId = null; + writeState(stateDir, state); +} diff --git a/pi-agent-plugin/src/dream/prompt.ts b/pi-agent-plugin/src/dream/prompt.ts new file mode 100644 index 000000000..4da1e7171 --- /dev/null +++ b/pi-agent-plugin/src/dream/prompt.ts @@ -0,0 +1,22 @@ +export const DREAM_PROTOCOL = ` +You are running memory consolidation. Complete these steps using the mem0_memory tool: + +1. ORIENT — Call mem0_memory with action "get_all" to list all memories. Count by category. Note oldest/newest. + +2. GATHER TARGETS — Review each memory. Classify as: + - DELETE: sensitive information (API keys, passwords, tokens), expired/stale entries, noise, redundant operational details + - MERGE: near-duplicates (same fact stated differently). Keep the better-worded one, delete the other. + - REWRITE: vague, first-person, or poorly-categorized entries. Use mem0_memory "add" with improved text, then "delete" the old one. + - KEEP: everything else. + Skip any memory starting with "[PINNED]". + +3. CONSOLIDATE — Execute the changes: + - Delete stale/duplicate entries + - For merges: add the merged text, delete both originals + - For rewrites: add improved version, delete original + +4. REPORT — Summarize: how many reviewed, deleted, merged, rewritten, final count. + +Quality targets: zero sensitive data stored, zero duplicates, all entries are atomic (one fact each), 15-50 words each. +After consolidation, respond to the user's message normally. +`; diff --git a/pi-agent-plugin/src/entry.test.ts b/pi-agent-plugin/src/entry.test.ts new file mode 100644 index 000000000..5e4ac25ed --- /dev/null +++ b/pi-agent-plugin/src/entry.test.ts @@ -0,0 +1,34 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { resolveUserId } from "./entry.ts"; + +describe("resolveUserId", () => { + const originalEnv = { ...process.env }; + + afterEach(() => { + process.env = { ...originalEnv }; + }); + + it("returns config userId when set", () => { + expect(resolveUserId("config-user")).toBe("config-user"); + }); + + it("falls back to USER env var", () => { + process.env.USER = "env-user"; + delete process.env.USERNAME; + expect(resolveUserId("")).toBe("env-user"); + }); + + it("falls back to USERNAME env var on Windows", () => { + delete process.env.USER; + process.env.USERNAME = "win-user"; + expect(resolveUserId("")).toBe("win-user"); + }); + + it("falls back to os.userInfo() when env vars are missing", () => { + delete process.env.USER; + delete process.env.USERNAME; + const result = resolveUserId(""); + expect(typeof result).toBe("string"); + expect(result.length).toBeGreaterThan(0); + }); +}); diff --git a/pi-agent-plugin/src/entry.ts b/pi-agent-plugin/src/entry.ts new file mode 100644 index 000000000..d02f7caeb --- /dev/null +++ b/pi-agent-plugin/src/entry.ts @@ -0,0 +1,146 @@ +import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; +import MemoryClient from "mem0ai"; +import { loadConfig, CONFIG_DIR } from "./config/index.ts"; +import { detectAppId, detectRunId, resolveSearchFilters } from "./memory/scoping.ts"; +import { registerMemoryTool } from "./memory/tools.ts"; +import { registerCommands } from "./commands.ts"; +import { setupAutoCapture } from "./capture/index.ts"; +import { MEMORY_POLICY } from "./prompt.ts"; +import { DREAM_PROTOCOL } from "./dream/prompt.ts"; +import { + incrementSessionCount, + checkCheapGates, + checkMemoryGate, + acquireDreamLock, + releaseDreamLock, + recordDreamCompletion, +} from "./dream/index.ts"; +import { captureEvent } from "./telemetry.ts"; +import * as os from "node:os"; +import type { ScopeContext } from "./types.ts"; + +export function resolveUserId(configUserId: string): string { + if (configUserId) return configUserId; + if (process.env.USER) return process.env.USER; + if (process.env.USERNAME) return process.env.USERNAME; + try { return os.userInfo().username; } catch { return "default"; } +} + +export default function mem0Extension(pi: ExtensionAPI): void { + const config = loadConfig(); + + if (!config.apiKey) { + console.warn("[mem0] No API key found. Set MEM0_API_KEY or add apiKey to ~/.pi/agent/mem0-config.json. Extension disabled."); + return; + } + + const mem0 = new MemoryClient({ apiKey: config.apiKey }); + + const scopeCtx: ScopeContext = { + userId: resolveUserId(config.userId), + appId: "", + runId: "unknown", + }; + + function getScopeCtx(): ScopeContext { + return scopeCtx; + } + + const telemetryCtx = { apiKey: config.apiKey }; + + // ── Register tool + commands + auto-capture ───────────────────────── + registerMemoryTool(pi, mem0, config, getScopeCtx, telemetryCtx); + registerCommands(pi, mem0, config, getScopeCtx, telemetryCtx); + setupAutoCapture(pi, mem0, config, getScopeCtx, telemetryCtx); + + captureEvent("pi.plugin.registered", { + auto_capture: config.autoCapture, + dream_enabled: config.dream.enabled, + default_scope: config.defaultScope, + }, telemetryCtx); + + // ── session_start: detect project + session, reconstruct scope ────── + pi.on("session_start", async (_event, ctx) => { + scopeCtx.appId = detectAppId(ctx.cwd); + + const sessionFile = ctx.sessionManager?.getSessionFile?.(); + scopeCtx.runId = detectRunId(sessionFile); + + if (config.userId) { + scopeCtx.userId = config.userId; + } + + if (config.dream.enabled) { + incrementSessionCount(CONFIG_DIR, scopeCtx.runId); + } + + captureEvent("pi.session.start", {}, telemetryCtx); + }); + + // ── before_agent_start: append memory policy + auto-dream trigger ─── + let dreamTriggered = false; + let dreamChecked = false; + + pi.on("before_agent_start", async (event, _ctx) => { + let extra = MEMORY_POLICY; + + if (config.dream.enabled && config.dream.auto && !dreamTriggered && !dreamChecked) { + const gates = checkCheapGates(CONFIG_DIR, config.dream); + if (gates.proceed) { + try { + const filters = resolveSearchFilters("project", scopeCtx); + const result = await mem0.getAll({ filters }); + const count = result.count ?? (result.results ?? []).length; + dreamChecked = true; + const memGate = checkMemoryGate(count, config.dream); + + if (memGate.pass && acquireDreamLock(CONFIG_DIR)) { + dreamTriggered = true; + extra += "\n\n" + DREAM_PROTOCOL; + captureEvent("pi.dream.triggered", { memory_count: count }, telemetryCtx); + } + } catch { + // Transient error — retry next turn + } + } + } + + return { + systemPrompt: (event.systemPrompt ?? "") + "\n\n" + extra, + }; + }); + + // ── agent_end: dream completion check ─────────────────────────────── + pi.on("agent_end", async (event) => { + if (!dreamTriggered) return; + + const messages = event.messages ?? []; + const hadWriteAction = messages.some((m) => { + if (m.role !== "assistant") return false; + const content = Array.isArray(m.content) ? m.content : []; + return content.some( + (block: any) => + block.type === "tool_use" && + block.name === "mem0_memory" && + ["add", "delete", "delete_all"].includes(block.input?.action), + ); + }); + + if (hadWriteAction) { + recordDreamCompletion(CONFIG_DIR); + captureEvent("pi.dream.completed", {}, telemetryCtx); + } + + releaseDreamLock(CONFIG_DIR); + dreamTriggered = false; + }); + + // ── session_shutdown: release dream lock if still held ────────────── + pi.on("session_shutdown", async () => { + captureEvent("pi.session.stop", {}, telemetryCtx); + if (dreamTriggered) { + releaseDreamLock(CONFIG_DIR); + dreamTriggered = false; + } + }); +} diff --git a/pi-agent-plugin/src/index.ts b/pi-agent-plugin/src/index.ts new file mode 100644 index 000000000..0da362d47 --- /dev/null +++ b/pi-agent-plugin/src/index.ts @@ -0,0 +1,34 @@ +export type { + Scope, + Mem0Config, + DreamConfig, + ScopeContext, + CustomCategory, +} from "./types.ts"; +export { DEFAULT_CUSTOM_CATEGORIES } from "./types.ts"; + +export { loadConfig, CONFIG_DIR } from "./config/index.ts"; + +export { registerMemoryTool, buildToolExecute } from "./memory/tools.ts"; +export { detectAppId, detectRunId, resolveSearchFilters, resolveAddParams } from "./memory/scoping.ts"; +export { formatAge, formatMemoryCompact, formatMemoryList, groupByCategory } from "./memory/formatting.ts"; + +export { setupAutoCapture, extractConversation } from "./capture/index.ts"; + +export { + incrementSessionCount, + checkCheapGates, + checkMemoryGate, + acquireDreamLock, + releaseDreamLock, + recordDreamCompletion, +} from "./dream/index.ts"; +export { DREAM_PROTOCOL } from "./dream/prompt.ts"; + +export { MEMORY_POLICY } from "./prompt.ts"; + +export { registerCommands } from "./commands.ts"; + +export { captureEvent, captureToolEvent, captureCommandEvent, _getEventQueue, _resetForTesting } from "./telemetry.ts"; + +export { default as mem0Extension } from "./entry.ts"; diff --git a/pi-agent-plugin/src/memory/formatting.ts b/pi-agent-plugin/src/memory/formatting.ts new file mode 100644 index 000000000..5d6bd3366 --- /dev/null +++ b/pi-agent-plugin/src/memory/formatting.ts @@ -0,0 +1,43 @@ +interface MemoryLike { + id: string; + memory?: string; + categories?: string[]; + createdAt?: Date | string; +} + +export function formatAge(date: Date | string): string { + const d = typeof date === "string" ? new Date(date) : date; + const ms = Date.now() - d.getTime(); + const minutes = Math.floor(ms / 60_000); + if (minutes < 60) return `${minutes}m ago`; + const hours = Math.floor(minutes / 60); + if (hours < 24) return `${hours}h ago`; + const days = Math.floor(hours / 24); + return `${days}d ago`; +} + +export function formatMemoryCompact(mem: MemoryLike): string { + const cat = mem.categories?.[0] ?? "uncategorized"; + const age = mem.createdAt ? ` (${formatAge(mem.createdAt)})` : ""; + return `[${cat}] ${mem.memory ?? "(empty)"}${age} [mem0:${mem.id}]`; +} + +export function formatMemoryList(memories: MemoryLike[]): string { + if (memories.length === 0) return "No memories found."; + return memories + .map((m, i) => `${i + 1}. ${formatMemoryCompact(m)}`) + .join("\n"); +} + +export function groupByCategory( + memories: MemoryLike[], +): Map { + const groups = new Map(); + for (const m of memories) { + const cat = m.categories?.[0] ?? "uncategorized"; + const list = groups.get(cat) ?? []; + list.push(m); + groups.set(cat, list); + } + return groups; +} diff --git a/pi-agent-plugin/src/memory/scoping.test.ts b/pi-agent-plugin/src/memory/scoping.test.ts new file mode 100644 index 000000000..ee843a176 --- /dev/null +++ b/pi-agent-plugin/src/memory/scoping.test.ts @@ -0,0 +1,85 @@ +import { describe, it, expect, vi, beforeEach } from "vitest"; +import { detectRunId, resolveSearchFilters, resolveAddParams } from "./scoping.ts"; + +const mockExecFileSync = vi.fn(); + +vi.mock("node:child_process", () => ({ + execFileSync: (...args: any[]) => mockExecFileSync(...args), +})); + +const { detectAppId } = await import("./scoping.ts"); + +describe("detectAppId", () => { + beforeEach(() => { + mockExecFileSync.mockReset(); + }); + + it("uses git root basename for a git repo", () => { + mockExecFileSync.mockReturnValue("/home/user/projects/my-app\n"); + expect(detectAppId("/home/user/projects/my-app")).toBe("my-app"); + }); + + it("returns same app_id from any subdirectory in a monorepo", () => { + mockExecFileSync.mockReturnValue("/home/user/projects/monorepo\n"); + const root = detectAppId("/home/user/projects/monorepo"); + const sub = detectAppId("/home/user/projects/monorepo/packages/core"); + expect(root).toBe("monorepo"); + expect(sub).toBe("monorepo"); + }); + + it("falls back to basename when not in a git repo", () => { + mockExecFileSync.mockImplementation(() => { + throw new Error("fatal: not a git repository"); + }); + expect(detectAppId("/home/user/scratch")).toBe("scratch"); + }); +}); + +describe("detectRunId", () => { + it("returns 'unknown' when no session file", () => { + expect(detectRunId(undefined)).toBe("unknown"); + }); + + it("returns a 12-char hex hash for a session file", () => { + const id = detectRunId("/tmp/session-abc.json"); + expect(id).toMatch(/^[0-9a-f]{12}$/); + }); + + it("produces different IDs for different session files", () => { + const a = detectRunId("/tmp/session-a.json"); + const b = detectRunId("/tmp/session-b.json"); + expect(a).not.toBe(b); + }); +}); + +describe("resolveSearchFilters", () => { + const ctx = { userId: "u1", appId: "a1", runId: "r1" }; + + it("includes user_id and app_id for project scope", () => { + expect(resolveSearchFilters("project", ctx)).toEqual({ user_id: "u1", app_id: "a1" }); + }); + + it("includes run_id for session scope", () => { + expect(resolveSearchFilters("session", ctx)).toEqual({ user_id: "u1", app_id: "a1", run_id: "r1" }); + }); + + it("uses wildcard app_id for global scope", () => { + expect(resolveSearchFilters("global", ctx)).toEqual({ user_id: "u1", app_id: "*" }); + }); +}); + +describe("resolveAddParams", () => { + const ctx = { userId: "u1", appId: "a1", runId: "r1" }; + + it("includes userId and appId for project scope", () => { + expect(resolveAddParams("project", ctx)).toEqual({ userId: "u1", appId: "a1" }); + }); + + it("includes runId for session scope", () => { + expect(resolveAddParams("session", ctx)).toEqual({ userId: "u1", appId: "a1", runId: "r1" }); + }); + + it("only includes userId for global scope", () => { + expect(resolveAddParams("global", ctx)).toEqual({ userId: "u1" }); + }); +}); diff --git a/pi-agent-plugin/src/memory/scoping.ts b/pi-agent-plugin/src/memory/scoping.ts new file mode 100644 index 000000000..8f5d2af44 --- /dev/null +++ b/pi-agent-plugin/src/memory/scoping.ts @@ -0,0 +1,51 @@ +import * as path from "node:path"; +import * as crypto from "node:crypto"; +import { execFileSync } from "node:child_process"; +import type { Scope, ScopeContext } from "../types.ts"; + +export function detectAppId(cwd: string): string { + try { + const root = execFileSync("git", ["rev-parse", "--show-toplevel"], { + cwd, + encoding: "utf-8", + timeout: 3000, + stdio: ["ignore", "pipe", "ignore"], + }).trim(); + return path.basename(root); + } catch { + return path.basename(cwd); + } +} + +export function detectRunId(sessionFile: string | undefined): string { + if (!sessionFile) return "unknown"; + return crypto.createHash("sha256").update(sessionFile).digest("hex").slice(0, 12); +} + +export function resolveSearchFilters( + scope: Scope, + ctx: ScopeContext, +): Record { + switch (scope) { + case "project": + return { user_id: ctx.userId, app_id: ctx.appId }; + case "session": + return { user_id: ctx.userId, app_id: ctx.appId, run_id: ctx.runId }; + case "global": + return { user_id: ctx.userId, app_id: "*" }; + } +} + +export function resolveAddParams( + scope: Scope, + ctx: ScopeContext, +): Record { + switch (scope) { + case "project": + return { userId: ctx.userId, appId: ctx.appId }; + case "session": + return { userId: ctx.userId, appId: ctx.appId, runId: ctx.runId }; + case "global": + return { userId: ctx.userId }; + } +} diff --git a/pi-agent-plugin/src/memory/tools.ts b/pi-agent-plugin/src/memory/tools.ts new file mode 100644 index 000000000..a61e68e1b --- /dev/null +++ b/pi-agent-plugin/src/memory/tools.ts @@ -0,0 +1,195 @@ +import type { ExtensionAPI } from "@earendil-works/pi-coding-agent"; +import { Type } from "typebox"; +import { StringEnum } from "@earendil-works/pi-ai"; +import type MemoryClient from "mem0ai"; +import type { Scope, ScopeContext, Mem0Config } from "../types.ts"; +import { DEFAULT_CUSTOM_CATEGORIES } from "../types.ts"; +import { resolveSearchFilters, resolveAddParams } from "./scoping.ts"; +import { formatMemoryList } from "./formatting.ts"; +import { captureToolEvent } from "../telemetry.ts"; + +interface MemoryResult { + message?: string; + eventId?: string; + status?: string; +} + +const MAX_OUTPUT_LINES = 200; +const MAX_OUTPUT_BYTES = 50_000; + +function truncateOutput(text: string): string { + const lines = text.split("\n"); + if (lines.length <= MAX_OUTPUT_LINES && text.length <= MAX_OUTPUT_BYTES) { + return text; + } + + const kept = lines.slice(0, MAX_OUTPUT_LINES); + let result = kept.join("\n"); + if (result.length > MAX_OUTPUT_BYTES) { + result = result.slice(0, MAX_OUTPUT_BYTES); + } + + const dropped = lines.length - kept.length; + if (dropped > 0 || text.length > MAX_OUTPUT_BYTES) { + result += `\n\n[Output truncated: showing ${kept.length} of ${lines.length} lines]`; + } + return result; +} + +interface ToolParams { + action: "search" | "add" | "get_all" | "update" | "delete" | "delete_all"; + query?: string; + content?: string; + memory_id?: string; + scope?: Scope; +} + +export function buildToolExecute( + mem0: MemoryClient, + scopeCtx: ScopeContext, + defaultScope: Scope, +) { + return async (params: ToolParams, signal?: AbortSignal) => { + const scope = params.scope ?? defaultScope; + + switch (params.action) { + case "search": { + if (signal?.aborted) throw new Error("Cancelled"); + if (!params.query) throw new Error("query is required for search"); + const filters = resolveSearchFilters(scope, scopeCtx); + const result = await mem0.search(params.query, { filters }); + const memories = result.results ?? []; + return { + content: [{ type: "text" as const, text: truncateOutput(formatMemoryList(memories)) }], + details: { matchCount: memories.length }, + }; + } + + case "add": { + if (signal?.aborted) throw new Error("Cancelled"); + if (!params.content) throw new Error("content is required for add"); + const addParams = resolveAddParams(scope, scopeCtx); + const result = await mem0.add( + [{ role: "user", content: params.content }], + { ...addParams, customCategories: DEFAULT_CUSTOM_CATEGORIES }, + ); + const res = result as MemoryResult; + const msg = res.message ?? "Memory stored."; + return { + content: [{ type: "text" as const, text: msg }], + details: { eventId: res.eventId ?? null, status: res.status ?? null }, + }; + } + + case "get_all": { + if (signal?.aborted) throw new Error("Cancelled"); + const filters = resolveSearchFilters(scope, scopeCtx); + const result = await mem0.getAll({ filters }); + const memories = result.results ?? []; + return { + content: [{ type: "text" as const, text: truncateOutput(formatMemoryList(memories)) }], + details: { totalCount: result.count ?? memories.length }, + }; + } + + case "update": { + if (signal?.aborted) throw new Error("Cancelled"); + if (!params.memory_id) throw new Error("memory_id is required for update"); + if (!params.content) throw new Error("content is required for update"); + const updateResult = await mem0.update(params.memory_id, { text: params.content }); + const res = updateResult as MemoryResult; + return { + content: [{ type: "text" as const, text: res.status ?? "Memory updated." }], + details: { memoryId: params.memory_id }, + }; + } + + case "delete": { + if (signal?.aborted) throw new Error("Cancelled"); + if (!params.memory_id) throw new Error("memory_id is required for delete"); + const result = await mem0.delete(params.memory_id); + return { + content: [{ type: "text" as const, text: result.message ?? "Memory deleted." }], + details: {}, + }; + } + + case "delete_all": { + if (signal?.aborted) throw new Error("Cancelled"); + const delParams = resolveAddParams(scope, scopeCtx); + const result = await mem0.deleteAll(delParams); + return { + content: [{ type: "text" as const, text: result.message ?? "All memories deleted." }], + details: {}, + }; + } + } + }; +} + +export function registerMemoryTool( + pi: ExtensionAPI, + mem0: MemoryClient, + config: Mem0Config, + getScopeCtx: () => ScopeContext, + telemetryCtx?: { apiKey?: string }, +): void { + pi.registerTool({ + name: "mem0_memory", + label: "Mem0 Memory", + description: + "Search, add, update, and manage persistent semantic memories powered by Mem0. Memories persist across sessions and devices. Output is truncated to 200 lines / 50KB.", + promptSnippet: "Semantic memory search and storage via Mem0", + promptGuidelines: [ + 'Use mem0_memory with action "search" when the user asks about past conversations, preferences, or decisions', + 'Use mem0_memory with action "add" to save important facts, preferences, goals, decisions, or lessons the user shares', + 'Use mem0_memory with action "update" to modify an existing memory — requires memory_id and content. Preserves the memory ID', + "Always use the default project scope unless the user EXPLICITLY asks to search across all projects — only then use scope \"global\"", + "Do NOT pass scope at all for normal queries — omitting it uses the project default automatically", + ], + parameters: Type.Object({ + action: StringEnum([ + "search", + "add", + "get_all", + "update", + "delete", + "delete_all", + ] as const), + query: Type.Optional( + Type.String({ description: "Search query or memory text" }), + ), + content: Type.Optional( + Type.String({ description: "Memory content to store or updated text" }), + ), + memory_id: Type.Optional( + Type.String({ description: "Memory ID for update or delete" }), + ), + scope: Type.Optional( + StringEnum(["project", "session", "global"] as const), + ), + }), + async execute(toolCallId, params, signal, onUpdate, ctx) { + const scopeCtx = getScopeCtx(); + const exec = buildToolExecute(mem0, scopeCtx, config.defaultScope); + const start = Date.now(); + try { + const result = await exec(params as ToolParams, signal); + const details = (result as any).details ?? {}; + captureToolEvent((params as ToolParams).action, { + success: true, + latency_ms: Date.now() - start, + result_count: details.matchCount ?? details.totalCount ?? undefined, + }, telemetryCtx); + return result; + } catch (err) { + captureToolEvent((params as ToolParams).action, { + success: false, + latency_ms: Date.now() - start, + error_type: err instanceof Error ? err.name : "unknown", + }, telemetryCtx); + throw err; + } + }, + }); +} diff --git a/pi-agent-plugin/src/prompt.ts b/pi-agent-plugin/src/prompt.ts new file mode 100644 index 000000000..ae3cd9bbc --- /dev/null +++ b/pi-agent-plugin/src/prompt.ts @@ -0,0 +1,16 @@ +export const MEMORY_POLICY = ` +You have persistent semantic memory via the mem0_memory tool, powered by Mem0. + +Memory is scoped to the current project by default. Do not change the scope unless explicitly asked. +- "project" (default): memories for this project — use this for all normal queries +- "session": memories from this session only +- "global": all memories across projects — ONLY use when the user explicitly asks for cross-project search + +When to use memory: +- Search when the user references past conversations, preferences, or decisions +- Save important facts, user preferences, key decisions, and lessons learned +- Check memory before asking the user something they may have already told you +- Save identity information, goals, relationships, and routines the user shares + +Memory persists across sessions and devices via Mem0's cloud. +`; diff --git a/pi-agent-plugin/src/telemetry.ts b/pi-agent-plugin/src/telemetry.ts new file mode 100644 index 000000000..f9c5eb568 --- /dev/null +++ b/pi-agent-plugin/src/telemetry.ts @@ -0,0 +1,240 @@ +/** + * Plugin telemetry — anonymous usage tracking via PostHog. + * + * Sends fire-and-forget events to PostHog using native fetch(). + * Events are batched and flushed every 5 seconds or when the queue + * reaches 10 events, whichever comes first. + * + * Disable with: MEM0_TELEMETRY=false + */ + +import { createHash, randomUUID } from "node:crypto"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import { CONFIG_DIR } from "./config/index.ts"; + +const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX"; +const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/"; + +const FLUSH_INTERVAL_MS = 5_000; +const FLUSH_THRESHOLD = 10; + +let eventQueue: Record[] = []; +let flushTimer: ReturnType | undefined; + +function _loadPluginVersion(): string { + try { + const pkgUrl = new URL("../package.json", import.meta.url); + const pkg = JSON.parse(fs.readFileSync(pkgUrl, "utf-8")); + return pkg.version ?? "unknown"; + } catch { + return "unknown"; + } +} + +const PLUGIN_VERSION = _loadPluginVersion(); + +// ── Opt-out ────────────────────────────────────────────────────────────── + +function isTelemetryEnabled(): boolean { + try { + const val = process.env.MEM0_TELEMETRY; + if (val !== undefined) { + const s = val.toLowerCase(); + return s !== "false" && s !== "0" && s !== "no" && s !== "off"; + } + return true; + } catch { + return true; + } +} + +// ── Identity ───────────────────────────────────────────────────────────── + +const TELEMETRY_ID_PATH = path.join(CONFIG_DIR, "mem0-telemetry-id.json"); + +let _cachedAnonymousId: string | undefined; + +function getOrCreateAnonymousId(): string { + if (_cachedAnonymousId) return _cachedAnonymousId; + try { + if (fs.existsSync(TELEMETRY_ID_PATH)) { + const data = JSON.parse(fs.readFileSync(TELEMETRY_ID_PATH, "utf-8")); + if (data.anonymousId) { + _cachedAnonymousId = data.anonymousId; + return _cachedAnonymousId!; + } + } + } catch { /* ignore */ } + + const newId = `pi-mem0-anon-${randomUUID().replace(/-/g, "")}`; + try { + fs.mkdirSync(CONFIG_DIR, { recursive: true }); + fs.writeFileSync(TELEMETRY_ID_PATH, JSON.stringify({ anonymousId: newId }), "utf-8"); + } catch { /* ignore */ } + _cachedAnonymousId = newId; + return newId; +} + +function getDistinctId(apiKey?: string): string { + if (apiKey) { + return createHash("sha256").update(apiKey).digest("hex"); + } + return getOrCreateAnonymousId(); +} + +let _identifyDone = false; + +function maybeBuildIdentifyEvent(distinctId: string): Record | null { + if (_identifyDone) return null; + if (!distinctId || distinctId.startsWith("pi-mem0-anon-")) return null; + try { + if (!fs.existsSync(TELEMETRY_ID_PATH)) { + _identifyDone = true; + return null; + } + const data = JSON.parse(fs.readFileSync(TELEMETRY_ID_PATH, "utf-8")); + const storedAnon = data.anonymousId; + if (!storedAnon) { + _identifyDone = true; + return null; + } + const identifyEvent = { + event: "$identify", + distinct_id: distinctId, + properties: { $anon_distinct_id: storedAnon, $lib: "posthog-node" }, + }; + try { + fs.unlinkSync(TELEMETRY_ID_PATH); + } catch { /* ignore */ } + _identifyDone = true; + _cachedAnonymousId = undefined; + return identifyEvent; + } catch { + return null; + } +} + +// ── Flush machinery ────────────────────────────────────────────────────── + +function ensureFlushTimer(): void { + if (flushTimer) return; + flushTimer = setInterval(flushEvents, FLUSH_INTERVAL_MS); + if (typeof flushTimer === "object" && "unref" in flushTimer) { + flushTimer.unref(); + } +} + +let _exitHandlerInstalled = false; + +function ensureExitHandler(): void { + if (_exitHandlerInstalled) return; + _exitHandlerInstalled = true; + process.on("beforeExit", async () => { + if (eventQueue.length === 0) return; + const batch = eventQueue; + eventQueue = []; + const body = JSON.stringify({ api_key: POSTHOG_API_KEY, batch }); + try { + await fetch(POSTHOG_HOST, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": String(Buffer.byteLength(body)), + }, + body, + signal: AbortSignal.timeout(3_000), + }); + } catch { /* silently swallow */ } + }); +} + +function flushEvents(): void { + if (eventQueue.length === 0) return; + const batch = eventQueue; + eventQueue = []; + + const body = JSON.stringify({ api_key: POSTHOG_API_KEY, batch }); + fetch(POSTHOG_HOST, { + method: "POST", + headers: { + "Content-Type": "application/json", + "Content-Length": String(Buffer.byteLength(body)), + }, + body, + signal: AbortSignal.timeout(3_000), + }).catch(() => { /* silently swallow */ }); +} + +// ── Public API ─────────────────────────────────────────────────────────── + +export function captureEvent( + eventName: string, + properties: Record = {}, + ctx?: { apiKey?: string }, +): void { + if (!isTelemetryEnabled()) return; + + try { + const distinctId = getDistinctId(ctx?.apiKey); + + const identifyEvent = maybeBuildIdentifyEvent(distinctId); + if (identifyEvent) { + eventQueue.push(identifyEvent); + } + + eventQueue.push({ + event: eventName, + distinct_id: distinctId, + properties: { + source: "PI_AGENT_PLUGIN", + language: "node", + plugin_version: PLUGIN_VERSION, + node_version: process.version, + os: process.platform, + $process_person_profile: false, + $lib: "posthog-node", + ...properties, + }, + }); + + ensureFlushTimer(); + ensureExitHandler(); + + if (eventQueue.length >= FLUSH_THRESHOLD) { + flushEvents(); + } + } catch { /* silently swallow */ } +} + +export function captureToolEvent( + action: string, + properties: Record = {}, + ctx?: { apiKey?: string }, +): void { + captureEvent("pi.tool.mem0_memory", { action, ...properties }, ctx); +} + +export function captureCommandEvent( + command: string, + properties: Record = {}, + ctx?: { apiKey?: string }, +): void { + captureEvent(`pi.command.${command}`, properties, ctx); +} + +// ── Test helpers ───────────────────────────────────────────────────────── + +export function _getEventQueue(): Record[] { + return eventQueue; +} + +export function _resetForTesting(): void { + eventQueue = []; + if (flushTimer) { + clearInterval(flushTimer); + flushTimer = undefined; + } + _cachedAnonymousId = undefined; + _identifyDone = false; +} diff --git a/pi-agent-plugin/src/types.ts b/pi-agent-plugin/src/types.ts new file mode 100644 index 000000000..482028c55 --- /dev/null +++ b/pi-agent-plugin/src/types.ts @@ -0,0 +1,52 @@ +export type Scope = "project" | "session" | "global"; + +export interface DreamConfig { + enabled: boolean; + auto: boolean; + minHours: number; + minSessions: number; + minMemories: number; +} + +export interface Mem0Config { + apiKey: string; + userId: string; + autoCapture: boolean; + defaultScope: Scope; + contextInjection: boolean; + dream: DreamConfig; +} + +export interface DreamState { + lastConsolidatedAt: number; + sessionsSince: number; + lastSessionId: string | null; +} + +export interface DreamLock { + pid: number; + startedAt: number; +} + +export interface ScopeContext { + userId: string; + appId: string; + runId: string; +} + +export interface CustomCategory { + [key: string]: string; +} + +export const DEFAULT_CUSTOM_CATEGORIES: CustomCategory[] = [ + { identity: "Personal details, background, and self-descriptions" }, + { preferences: "Likes, dislikes, habits, and preferred ways of doing things" }, + { goals: "Objectives, aspirations, and targets the user is working toward" }, + { projects: "Ongoing work, initiatives, and areas of focus" }, + { decisions: "Choices made, rationale, and trade-offs considered" }, + { technical: "Technical knowledge, tools, configurations, and environment details" }, + { relationships: "People, teams, organizations, and their roles" }, + { routines: "Recurring patterns, workflows, schedules, and processes" }, + { lessons: "Insights learned, mistakes to avoid, and best practices discovered" }, + { work: "Professional context, role, responsibilities, and work environment" }, +]; diff --git a/pi-agent-plugin/tests/capture.test.ts b/pi-agent-plugin/tests/capture.test.ts new file mode 100644 index 000000000..6f07b3035 --- /dev/null +++ b/pi-agent-plugin/tests/capture.test.ts @@ -0,0 +1,62 @@ +import { describe, it, expect } from "vitest"; +import { extractConversation } from "../src/capture/index.ts"; + +describe("extractConversation", () => { + it("extracts user and assistant text messages", () => { + const messages = [ + { role: "user", content: "Hello" }, + { role: "assistant", content: "Hi there!" }, + ]; + const result = extractConversation(messages); + expect(result).toHaveLength(2); + expect(result[0]).toEqual({ role: "user", content: "Hello" }); + expect(result[1]).toEqual({ role: "assistant", content: "Hi there!" }); + }); + + it("skips assistant tool_use blocks, keeps text blocks", () => { + const messages = [ + { role: "user", content: "Search" }, + { role: "assistant", content: [{ type: "tool_use", id: "x", name: "mem0" }] }, + { role: "tool", content: "results" }, + { role: "assistant", content: "Here are the results" }, + ]; + const result = extractConversation(messages); + expect(result).toHaveLength(2); + expect(result[0]).toEqual({ role: "user", content: "Search" }); + expect(result[1]).toEqual({ role: "assistant", content: "Here are the results" }); + }); + + it("extracts text from content arrays for both roles", () => { + const messages = [ + { role: "user", content: [{ type: "text", text: "Hello world" }] }, + { role: "assistant", content: [{ type: "text", text: "Response" }, { type: "tool_use", id: "x" }] }, + ]; + const result = extractConversation(messages); + expect(result).toHaveLength(2); + expect(result[0].content).toBe("Hello world"); + expect(result[1].content).toBe("Response"); + }); + + it("skips tool and system messages", () => { + const messages = [ + { role: "system", content: "You are helpful" }, + { role: "user", content: "Hi" }, + { role: "tool", content: "tool output" }, + ]; + const result = extractConversation(messages); + expect(result).toHaveLength(1); + expect(result[0]).toEqual({ role: "user", content: "Hi" }); + }); + + it("skips assistant messages with only tool_use (no text)", () => { + const messages = [ + { role: "assistant", content: [{ type: "tool_use", id: "x", name: "bash" }] }, + ]; + const result = extractConversation(messages); + expect(result).toHaveLength(0); + }); + + it("returns empty array for empty input", () => { + expect(extractConversation([])).toEqual([]); + }); +}); diff --git a/pi-agent-plugin/tests/config.test.ts b/pi-agent-plugin/tests/config.test.ts new file mode 100644 index 000000000..434210938 --- /dev/null +++ b/pi-agent-plugin/tests/config.test.ts @@ -0,0 +1,59 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import * as fs from "node:fs"; +import { loadConfig } from "../src/config/index.ts"; + +vi.mock("node:fs"); + +describe("loadConfig", () => { + const originalEnv = process.env; + + beforeEach(() => { + process.env = { ...originalEnv, HOME: "/home/testuser" }; + vi.mocked(fs.existsSync).mockReturnValue(false); + }); + + afterEach(() => { + process.env = originalEnv; + vi.restoreAllMocks(); + }); + + it("reads config from env vars when no config file exists", () => { + process.env.MEM0_API_KEY = "m0-test-key"; + process.env.MEM0_USER_ID = "env-user"; + const config = loadConfig(); + expect(config.apiKey).toBe("m0-test-key"); + expect(config.userId).toBe("env-user"); + expect(config.autoCapture).toBe(true); + expect(config.defaultScope).toBe("project"); + }); + + it("returns empty apiKey when no key found anywhere", () => { + delete process.env.MEM0_API_KEY; + const config = loadConfig(); + expect(config.apiKey).toBe(""); + }); + + it("reads config file and merges with defaults", () => { + delete process.env.MEM0_API_KEY; + delete process.env.MEM0_USER_ID; + vi.mocked(fs.existsSync).mockReturnValue(true); + vi.mocked(fs.readFileSync).mockReturnValue( + JSON.stringify({ apiKey: "m0-file-key", userId: "file-user" }) + ); + const config = loadConfig(); + expect(config.apiKey).toBe("m0-file-key"); + expect(config.userId).toBe("file-user"); + expect(config.dream.enabled).toBe(true); + expect(config.dream.minHours).toBe(24); + }); + + it("env vars override config file", () => { + process.env.MEM0_API_KEY = "m0-env-key"; + vi.mocked(fs.existsSync).mockReturnValue(true); + vi.mocked(fs.readFileSync).mockReturnValue( + JSON.stringify({ apiKey: "m0-file-key" }) + ); + const config = loadConfig(); + expect(config.apiKey).toBe("m0-env-key"); + }); +}); diff --git a/pi-agent-plugin/tests/dream.test.ts b/pi-agent-plugin/tests/dream.test.ts new file mode 100644 index 000000000..42c40223c --- /dev/null +++ b/pi-agent-plugin/tests/dream.test.ts @@ -0,0 +1,59 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import * as fs from "node:fs"; +import { checkCheapGates, checkMemoryGate } from "../src/dream/index.ts"; + +vi.mock("node:fs"); + +const STATE_DIR = "/tmp/test-mem0-dream"; + +describe("checkCheapGates", () => { + beforeEach(() => { + vi.mocked(fs.mkdirSync).mockReturnValue(undefined); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("blocks when no state file exists (zero sessions)", () => { + vi.mocked(fs.readFileSync).mockImplementation(() => { throw new Error("ENOENT"); }); + const result = checkCheapGates(STATE_DIR, {}); + expect(result.proceed).toBe(false); + expect(result.reason).toContain("sessions"); + }); + + it("blocks when consolidated recently", () => { + vi.mocked(fs.readFileSync).mockReturnValue( + JSON.stringify({ lastConsolidatedAt: Date.now() - 3_600_000, sessionsSince: 10, lastSessionId: null }) + ); + const result = checkCheapGates(STATE_DIR, {}); + expect(result.proceed).toBe(false); + expect(result.reason).toContain("time"); + }); + + it("blocks when not enough sessions", () => { + vi.mocked(fs.readFileSync).mockReturnValue( + JSON.stringify({ lastConsolidatedAt: Date.now() - 48 * 3_600_000, sessionsSince: 2, lastSessionId: null }) + ); + const result = checkCheapGates(STATE_DIR, {}); + expect(result.proceed).toBe(false); + expect(result.reason).toContain("sessions"); + }); + + it("proceeds when both gates pass", () => { + vi.mocked(fs.readFileSync).mockReturnValue( + JSON.stringify({ lastConsolidatedAt: Date.now() - 48 * 3_600_000, sessionsSince: 10, lastSessionId: null }) + ); + expect(checkCheapGates(STATE_DIR, {}).proceed).toBe(true); + }); +}); + +describe("checkMemoryGate", () => { + it("blocks when too few memories", () => { + expect(checkMemoryGate(5, {}).pass).toBe(false); + }); + + it("passes when enough memories", () => { + expect(checkMemoryGate(25, {}).pass).toBe(true); + }); +}); diff --git a/pi-agent-plugin/tests/formatting.test.ts b/pi-agent-plugin/tests/formatting.test.ts new file mode 100644 index 000000000..1147fbfb3 --- /dev/null +++ b/pi-agent-plugin/tests/formatting.test.ts @@ -0,0 +1,47 @@ +import { describe, it, expect } from "vitest"; +import { formatAge, formatMemoryCompact, formatMemoryList } from "../src/memory/formatting.ts"; + +describe("formatAge", () => { + it("formats minutes", () => { + expect(formatAge(new Date(Date.now() - 30 * 60_000))).toBe("30m ago"); + }); + + it("formats hours", () => { + expect(formatAge(new Date(Date.now() - 3 * 3_600_000))).toBe("3h ago"); + }); + + it("formats days", () => { + expect(formatAge(new Date(Date.now() - 5 * 86_400_000))).toBe("5d ago"); + }); +}); + +describe("formatMemoryCompact", () => { + it("formats a memory as a single line", () => { + const mem = { + id: "abc-123-def-456", + memory: "User prefers dark mode", + categories: ["preference"], + createdAt: new Date(), + }; + const line = formatMemoryCompact(mem); + expect(line).toContain("[preference]"); + expect(line).toContain("User prefers dark mode"); + expect(line).toContain("[mem0:abc-123-def-456]"); + }); +}); + +describe("formatMemoryList", () => { + it("formats multiple memories with numbering", () => { + const memories = [ + { id: "id-1", memory: "Fact one", categories: ["insight"], createdAt: new Date() }, + { id: "id-2", memory: "Fact two", categories: ["convention"], createdAt: new Date() }, + ]; + const output = formatMemoryList(memories); + expect(output).toContain("1."); + expect(output).toContain("2."); + }); + + it("returns empty message for no memories", () => { + expect(formatMemoryList([])).toBe("No memories found."); + }); +}); diff --git a/pi-agent-plugin/tests/scoping.test.ts b/pi-agent-plugin/tests/scoping.test.ts new file mode 100644 index 000000000..9cf468216 --- /dev/null +++ b/pi-agent-plugin/tests/scoping.test.ts @@ -0,0 +1,47 @@ +import { describe, it, expect } from "vitest"; +import { resolveAddParams, resolveSearchFilters } from "../src/memory/scoping.ts"; +import type { ScopeContext } from "../src/types.ts"; + +const ctx: ScopeContext = { + userId: "kartik", + appId: "my-project", + runId: "session-abc123", +}; + +describe("resolveSearchFilters", () => { + it("project scope returns user_id + app_id", () => { + expect(resolveSearchFilters("project", ctx)).toEqual({ + user_id: "kartik", app_id: "my-project", + }); + }); + + it("session scope returns user_id + app_id + run_id", () => { + expect(resolveSearchFilters("session", ctx)).toEqual({ + user_id: "kartik", app_id: "my-project", run_id: "session-abc123", + }); + }); + + it("global scope returns user_id with app_id wildcard", () => { + expect(resolveSearchFilters("global", ctx)).toEqual({ + user_id: "kartik", app_id: "*", + }); + }); +}); + +describe("resolveAddParams", () => { + it("project scope returns userId + appId (camelCase)", () => { + expect(resolveAddParams("project", ctx)).toEqual({ + userId: "kartik", appId: "my-project", + }); + }); + + it("session scope includes runId", () => { + expect(resolveAddParams("session", ctx)).toEqual({ + userId: "kartik", appId: "my-project", runId: "session-abc123", + }); + }); + + it("global scope returns userId only", () => { + expect(resolveAddParams("global", ctx)).toEqual({ userId: "kartik" }); + }); +}); diff --git a/pi-agent-plugin/tests/telemetry.test.ts b/pi-agent-plugin/tests/telemetry.test.ts new file mode 100644 index 000000000..e842ec3ef --- /dev/null +++ b/pi-agent-plugin/tests/telemetry.test.ts @@ -0,0 +1,122 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; + +vi.mock("node:fs", () => ({ + existsSync: vi.fn().mockReturnValue(false), + readFileSync: vi.fn().mockReturnValue("{}"), + writeFileSync: vi.fn(), + mkdirSync: vi.fn(), + unlinkSync: vi.fn(), +})); + +import { + captureEvent, + captureToolEvent, + captureCommandEvent, + _getEventQueue, + _resetForTesting, +} from "../src/telemetry.ts"; + +describe("telemetry", () => { + let fetchSpy: ReturnType; + + beforeEach(() => { + delete process.env.MEM0_TELEMETRY; + _resetForTesting(); + fetchSpy = vi.fn().mockResolvedValue({ ok: true }); + vi.stubGlobal("fetch", fetchSpy); + }); + + afterEach(() => { + vi.restoreAllMocks(); + delete process.env.MEM0_TELEMETRY; + }); + + it("queues an event with correct name and standard properties", () => { + captureEvent("pi.test.event", { custom: 42 }); + const queue = _getEventQueue(); + expect(queue).toHaveLength(1); + expect(queue[0].event).toBe("pi.test.event"); + const props = queue[0].properties as Record; + expect(props.source).toBe("PI_AGENT_PLUGIN"); + expect(props.language).toBe("node"); + expect(props.custom).toBe(42); + expect(props.$process_person_profile).toBe(false); + }); + + it("uses SHA-256 of apiKey as distinct_id when provided", () => { + captureEvent("test", {}, { apiKey: "m0-testkey" }); + const queue = _getEventQueue(); + expect(queue[0].distinct_id).toMatch(/^[a-f0-9]{64}$/); + expect(queue[0].distinct_id).not.toBe("m0-testkey"); + }); + + it("generates a persistent anonymous id when no apiKey", () => { + captureEvent("test", {}, {}); + const queue = _getEventQueue(); + expect(queue[0].distinct_id).toMatch(/^pi-mem0-anon-/); + }); + + it("does not queue events when MEM0_TELEMETRY=false", () => { + process.env.MEM0_TELEMETRY = "false"; + captureEvent("should.not.appear"); + expect(_getEventQueue()).toHaveLength(0); + }); + + it("does not queue events when MEM0_TELEMETRY=0", () => { + process.env.MEM0_TELEMETRY = "0"; + captureEvent("should.not.appear"); + expect(_getEventQueue()).toHaveLength(0); + }); + + it("does not queue events when MEM0_TELEMETRY=off", () => { + process.env.MEM0_TELEMETRY = "off"; + captureEvent("should.not.appear"); + expect(_getEventQueue()).toHaveLength(0); + }); + + it("re-enables telemetry when env var is cleared between calls", () => { + process.env.MEM0_TELEMETRY = "false"; + captureEvent("blocked"); + expect(_getEventQueue()).toHaveLength(0); + + delete process.env.MEM0_TELEMETRY; + captureEvent("allowed"); + expect(_getEventQueue()).toHaveLength(1); + expect(_getEventQueue()[0].event).toBe("allowed"); + }); + + it("flushes via fetch when queue reaches threshold", () => { + for (let i = 0; i < 10; i++) { + captureEvent(`event_${i}`); + } + expect(fetchSpy).toHaveBeenCalledTimes(1); + expect(_getEventQueue()).toHaveLength(0); + }); + + it("captureToolEvent uses pi.tool.mem0_memory event name with action property", () => { + captureToolEvent("search", { success: true, latency_ms: 42 }); + const queue = _getEventQueue(); + expect(queue).toHaveLength(1); + expect(queue[0].event).toBe("pi.tool.mem0_memory"); + const props = queue[0].properties as Record; + expect(props.action).toBe("search"); + expect(props.success).toBe(true); + expect(props.latency_ms).toBe(42); + }); + + it("captureCommandEvent uses pi.command. event name", () => { + captureCommandEvent("mem0-search", { result_count: 5 }); + const queue = _getEventQueue(); + expect(queue).toHaveLength(1); + expect(queue[0].event).toBe("pi.command.mem0-search"); + const props = queue[0].properties as Record; + expect(props.result_count).toBe(5); + }); + + it("never throws even if fetch throws", () => { + fetchSpy.mockRejectedValueOnce(new Error("network down")); + expect(() => { + for (let i = 0; i < 10; i++) captureEvent(`event_${i}`); + }).not.toThrow(); + }); +}); diff --git a/pi-agent-plugin/tests/tools.test.ts b/pi-agent-plugin/tests/tools.test.ts new file mode 100644 index 000000000..f9b753ef5 --- /dev/null +++ b/pi-agent-plugin/tests/tools.test.ts @@ -0,0 +1,61 @@ +import { describe, it, expect, vi } from "vitest"; +import { buildToolExecute } from "../src/memory/tools.ts"; +import type { ScopeContext } from "../src/types.ts"; + +const mockMem0 = { + search: vi.fn(), + add: vi.fn(), + getAll: vi.fn(), + delete: vi.fn(), + deleteAll: vi.fn(), +}; + +const scopeCtx: ScopeContext = { + userId: "testuser", + appId: "testproject", + runId: "session123", +}; + +describe("buildToolExecute", () => { + const execute = buildToolExecute(mockMem0 as any, scopeCtx, "project"); + + it("search calls mem0.search with correct filters", async () => { + mockMem0.search.mockResolvedValue({ results: [] }); + await execute({ action: "search", query: "dark mode" }); + expect(mockMem0.search).toHaveBeenCalledWith("dark mode", { + filters: { user_id: "testuser", app_id: "testproject" }, + }); + }); + + it("add calls mem0.add with customCategories and entity params", async () => { + mockMem0.add.mockResolvedValue([{ id: "new-id", memory: "test" }]); + await execute({ action: "add", content: "User likes tabs" }); + const call = mockMem0.add.mock.calls[0]; + expect(call[0]).toEqual([{ role: "user", content: "User likes tabs" }]); + expect(call[1].userId).toBe("testuser"); + expect(call[1].appId).toBe("testproject"); + expect(call[1].customCategories).toBeDefined(); + expect(call[1].customCategories.length).toBe(10); + }); + + it("search with scope=global filters by user_id with app_id wildcard", async () => { + mockMem0.search.mockResolvedValue({ results: [] }); + await execute({ action: "search", query: "preferences", scope: "global" }); + expect(mockMem0.search).toHaveBeenCalledWith("preferences", { + filters: { user_id: "testuser", app_id: "*" }, + }); + }); + + it("delete calls mem0.delete with full memory_id", async () => { + mockMem0.delete.mockResolvedValue({ message: "deleted" }); + await execute({ action: "delete", memory_id: "abc12345-6789-0abc-def0-123456789abc" }); + expect(mockMem0.delete).toHaveBeenCalledWith("abc12345-6789-0abc-def0-123456789abc"); + }); + + it("delete passes memory_id directly to mem0.delete", async () => { + const fullId = "956e3d68-b420-4e07-a4e3-3019e7cebe6f"; + mockMem0.delete.mockResolvedValue({ message: "deleted" }); + await execute({ action: "delete", memory_id: fullId }); + expect(mockMem0.delete).toHaveBeenCalledWith(fullId); + }); +}); diff --git a/pi-agent-plugin/tsconfig.json b/pi-agent-plugin/tsconfig.json new file mode 100644 index 000000000..8808fe6ed --- /dev/null +++ b/pi-agent-plugin/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "ignoreDeprecations": "6.0", + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "dist", + "rootDir": "src", + "strict": true, + "types": ["node"], + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "allowImportingTsExtensions": true, + "noEmit": true + }, + "include": ["src"], + "exclude": ["node_modules", "dist", "**/*.test.ts"] +} diff --git a/pi-agent-plugin/tsup.config.ts b/pi-agent-plugin/tsup.config.ts new file mode 100644 index 000000000..22984f5e8 --- /dev/null +++ b/pi-agent-plugin/tsup.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["src/index.ts", "src/entry.ts"], + format: ["esm"], + splitting: true, + dts: true, + sourcemap: true, + clean: true, + external: [ + /^node:/, + /^@earendil-works\//, + "typebox", + "mem0ai", + /^mem0ai\//, + ], +}); diff --git a/pi-agent-plugin/vitest.config.ts b/pi-agent-plugin/vitest.config.ts new file mode 100644 index 000000000..e2ec33294 --- /dev/null +++ b/pi-agent-plugin/vitest.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globals: true, + }, +});