diff --git a/CHANGELOG.md b/CHANGELOG.md index 33984bcca..3f5fc793c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,37 +1,17 @@ # Changelog -## 2026.1.12-1 +## 2026.1.12 + +### Highlights +- Memory: add vector search for agent memories (Markdown-only scope) with SQLite index, chunking, lazy sync + file watch, and per-agent enablement/fallback. ### Changes -- Heartbeat: raise default `ackMaxChars` to 300 so any `HEARTBEAT_OK` replies with short padding stay internal (fewer noisy heartbeat posts on providers). -- Onboarding: normalize API key inputs (strip `export KEY=...` wrappers) so shell-style entries paste cleanly. - -## 2026.1.11-5 +- Memory: embedding providers support OpenAI or local `node-llama-cpp`; config adds defaults + per-agent overrides, provider/fallback metadata surfaced in tools/CLI. +- CLI/Tools: new `clawdbot memory` commands plus `memory_search`/`memory_get` tools returning snippets + line ranges and provider info. +- Runtime: memory index stored under `~/.clawdbot/memory/{agentId}.sqlite` with watch-on-by-default; inline status replies now stay auth-gated while inline prompts continue to the agent. ### Fixes -- Auto-reply: prevent duplicate /status replies (including /usage alias) and add tests for inline + standalone cases. - -## 2026.1.11-4 - -### Fixes -- CLI: read the git commit hash from the package root so npm installs show it. - -## 2026.1.11-3 - -### Fixes -- CLI: avoid top-level await warnings in the entrypoint on fresh installs. -- CLI: show a commit hash in the banner for npm installs (package.json gitHead fallback). - -## 2026.1.11-2 - -### Fixes -- Installer: ensure the CLI entrypoint is executable after npm installs. -- Packaging: include `dist/plugins/` in the npm package to avoid missing module errors. - -## 2026.1.11-1 - -### Fixes -- Installer: include `patches/` in the npm package so postinstall patching works for npm/bun installs. +- Auto-reply: inline `/status` now honors allowlists (authorized stripped + replied inline; unauthorized leaves text for the agent) to match command gating tests. ## 2026.1.11 @@ -42,9 +22,6 @@ - Agents: automatic pre-compaction memory flush turn to store durable memories before compaction. ### Changes -- Deps: update pi-agent-core/pi-ai/pi-coding-agent/pi-tui and refresh the pi-ai patch. -- Dev: bump @types/node. -- macOS: add wizard debug CLI and share wizard parsing helpers. - CLI/Onboarding: simplify MiniMax auth choice to a single M2.1 option. - CLI: configure section selection now loops until Continue. - Docs: explain MiniMax vs MiniMax Lightning (speed vs cost) and restore LM Studio example. @@ -52,20 +29,16 @@ - Onboarding/CLI: group model/auth choice by provider and label Z.AI as GLM 4.7. - Onboarding/Docs: add Moonshot AI (Kimi K2) auth choice + config example. - CLI/Onboarding: prompt to reuse detected API keys for Moonshot/MiniMax/Z.AI/Gemini/Anthropic/OpenCode. -- CLI/Onboarding: move MiniMax to the top of the provider list. -- CLI/Onboarding: add MiniMax M2.1 Lightning auth choice. -- CLI/Onboarding: show key previews when reusing detected API keys. - Auto-reply: add compact `/model` picker (models + available providers) and show provider endpoints in `/model status`. - Control UI: add Config tab model presets (MiniMax M2.1, GLM 4.7, Kimi) for one-click setup. - Plugins: add extension loader (tools/RPC/CLI/services), discovery paths, and config schema + Control UI labels (uiHints). - Plugins: add `clawdbot plugins install` (path/tgz/npm), plus `list|info|enable|disable|doctor` UX. - Plugins: voice-call plugin now real (Twilio/log), adds start/status RPC/CLI/tool + tests. - Docs: add plugins doc + cross-links from tools/skills/gateway config. -- Docs: clarify memory flush behavior + writable workspace requirement in Memory/Session/FAQ. - Docs: add beginner-friendly plugin quick start + expand Voice Call plugin docs. - Tests: add Docker plugin loader + tgz-install smoke test. - Tests: extend Docker plugin E2E to cover installing from local folders (`plugins.load.paths`) and `file:` npm specs. -- Tests: add coverage for pre-compaction memory flush settings (including read-only/CLI skips). +- Tests: add coverage for pre-compaction memory flush settings. - Tests: modernize live model smoke selection for current releases and enforce tools/images/thinking-high coverage. (#769) — thanks @steipete. - Agents/Tools: add `apply_patch` tool for multi-file edits (experimental; gated by tools.exec.applyPatch; OpenAI-only). - Agents/Tools: rename the bash tool to exec (config alias maintained). (#748) — thanks @myfunc. @@ -92,17 +65,9 @@ - Installer UX: add `--install-method git|npm` and auto-detect source checkouts (prompt to update git checkout vs migrate to npm). ### Fixes -- Control UI: flatten nav into a single horizontal scroll row on tablet/mobile (and always show collapsed group items). (#771) — thanks @carlulsoe. -- macOS: start + await local gateway before onboarding wizard begins. -- macOS: cancel onboarding wizard on close, recover if the gateway drops the session, and time out stalled gateway connects. -- macOS: wizard debug CLI now surfaces error status instead of exiting as complete. - Models/Onboarding: configure MiniMax (minimax.io) via Anthropic-compatible `/anthropic` endpoint by default (keep `minimax-api` as a legacy alias). -- Agents/Browser: cap Playwright AI snapshots for tool calls (maxChars); CLI snapshots remain full. (#763) — thanks @thesash. - Models: normalize Gemini 3 Pro/Flash IDs to preview names for live model lookups. (#769) — thanks @steipete. - CLI: fix guardCancel typing for configure prompts. (#769) — thanks @steipete. -- Providers: default groupPolicy to allowlist across providers and warn in doctor when groups are open. -- MS Teams: add groupPolicy/groupAllowFrom gating for group chats and warn when groups are open. -- Providers: strip tool call/result ids from Gemini CLI payloads to avoid API 400s. (#756) - Gateway/WebChat: include handshake validation details in the WebSocket close reason for easier debugging; preserve close codes. - Gateway/Auth: send invalid connect responses before closing the handshake; stabilize invalid-connect auth test. - Gateway: tighten gateway listener detection. @@ -114,23 +79,16 @@ - Config: expand `~` in `CLAWDBOT_CONFIG_PATH` and common path-like config fields (including `plugins.load.paths`); guard invalid `$include` paths. (#731) — thanks @pasogott. - Agents: stop pre-creating session transcripts so first user messages persist in JSONL history. - Agents: skip pre-compaction memory flush when the session workspace is read-only. -- Auto-reply: allow inline `/status` for allowlisted senders (stripped before the model); unauthorized senders see it as plain text. -- Auto-reply: include config-only allowlisted models in `/model` even when the catalog is partial. -- Auto-reply: allow fuzzy `/model` matches (e.g. `/model kimi` or `/model moonshot/kimi`) when unambiguous. - Auto-reply: ignore inline `/status` directives unless the message is directive-only. -- CLI/Configure: enter the selected section immediately, then return to the section picker. -- CLI/Configure: apply the chosen auth model as default (skip the extra picker) and refresh the model catalog for new providers. - Auto-reply: align `/think` default display with model reasoning defaults. (#751) — thanks @gabriel-trigo. - Auto-reply: flush block reply buffers on tool boundaries. (#750) — thanks @sebslight. - Auto-reply: allow sender fallback for command authorization when `SenderId` is empty (WhatsApp self-chat). (#755) — thanks @juanpablodlc. - Heartbeat: refresh prompt text for updated defaults. - Agents/Tools: use PowerShell on Windows to capture system utility output. (#748) — thanks @myfunc. -- Agents/Tools: normalize Claude Code-style read/write/edit params (file_path/old_string/new_string) and keep sandbox guards in place. (#768) — thanks @hsrvc. - Docker: tolerate unset optional env vars in docker-setup.sh under strict mode. (#725) — thanks @petradonka. - CLI/Update: preserve base environment when passing overrides to update subprocesses. (#713) — thanks @danielz1z. - Agents: treat message tool errors as failures so fallback replies still send; require `to` + `message` for `action=send`. (#717) — thanks @theglove44. - Agents: preserve reasoning items on tool-only turns. -- Agents: enforce `` gating for reasoning-tag providers to prevent tag/reasoning leaks. (#754) — thanks @mcinteerj. - Agents/Subagents: wait for completion before announcing, align wait timeout with run timeout, and make announce prompts more emphatic. - Agents: route subagent transcripts to the target agent sessions directory and add regression coverage. (#708) — thanks @xMikeMickelson. - Agents/Tools: preserve action enums when flattening tool schemas. (#708) — thanks @xMikeMickelson. diff --git a/docs/cli/index.md b/docs/cli/index.md index 9d168ea83..cf759d672 100644 --- a/docs/cli/index.md +++ b/docs/cli/index.md @@ -70,6 +70,10 @@ clawdbot [--dev] [--profile ] enable disable doctor + memory + status + index + search message agent agents @@ -188,6 +192,14 @@ Manage extensions and their config: Most plugin changes require a gateway restart. See [/plugin](/plugin). +## Memory + +Vector search over `MEMORY.md` + `memory/*.md`: + +- `clawdbot memory status` — show index stats. +- `clawdbot memory index` — reindex memory files. +- `clawdbot memory search ""` — semantic search over memory. + ## Chat slash commands Chat messages support `/...` commands (text and native). See [/tools/slash-commands](/tools/slash-commands). diff --git a/docs/concepts/memory.md b/docs/concepts/memory.md index 246987400..948ba8284 100644 --- a/docs/concepts/memory.md +++ b/docs/concepts/memory.md @@ -67,3 +67,38 @@ Details: For the full compaction lifecycle, see [Session management + compaction](/reference/session-management-compaction). + +## Vector memory search + +Clawdbot can build a small vector index over `MEMORY.md` and `memory/*.md` so +semantic queries can find related notes even when wording differs. + +Defaults: +- Enabled by default. +- Watches memory files for changes (debounced). +- Uses remote embeddings (OpenAI) unless configured for local. +- Local mode uses node-llama-cpp and may require `pnpm approve-builds`. + +Config example: + +```json5 +agents: { + defaults: { + memorySearch: { + provider: "openai", + model: "text-embedding-3-small", + fallback: "openai", + sync: { watch: true } + } + } +} +``` + +Tools: +- `memory_search` — returns snippets with file + line ranges. +- `memory_get` — read memory file content by path. + +Local mode: +- Set `agents.defaults.memorySearch.provider = "local"`. +- Provide `agents.defaults.memorySearch.local.modelPath` (GGUF or `hf:` URI). +- Optional: set `agents.defaults.memorySearch.fallback = "none"` to avoid remote fallback. diff --git a/docs/refactor/vector-memory.md b/docs/refactor/vector-memory.md new file mode 100644 index 000000000..e4c8e545e --- /dev/null +++ b/docs/refactor/vector-memory.md @@ -0,0 +1,127 @@ +--- +summary: "Vector memory search design plan (per-agent, watch/lazy sync, storage)" +read_when: + - Designing or implementing vector memory search + - Adding embedding providers or sync behavior +--- + +# Vector Memory Search — Design Plan + +Goal: semantic search over **agent memory files** only, with minimal deps and +good UX defaults. Default enabled. Per-agent overrides. + +## Scope +- Sources: `MEMORY.md` + `memory/YYYY-MM-DD.md` inside the agent workspace. +- No indexing outside the workspace. No hidden paths. +- No QMD-style query expansion or rerank in v1. + +## Config Shape +Location: `agents.defaults.memorySearch` + `agents.list[].memorySearch`. + +```json5 +agents: { + defaults: { + memorySearch: { + enabled: true, + provider: "openai", // "openai" | "local" + fallback: "openai", // "openai" | "none" + model: "text-embedding-3-small", + store: { + driver: "sqlite", + path: "~/.clawdbot/memory/{agentId}.sqlite" + }, + chunking: { + tokens: 400, + overlap: 80 + }, + sync: { + onSessionStart: true, + onSearch: true, // LazySync + watch: true, // default on + watchDebounceMs: 1500, + intervalMinutes: 0 + }, + query: { + maxResults: 6, + minScore: 0.35 + } + } + }, + list: [ + { id: "peter", memorySearch: { provider: "local", sync: { watch: false } } } + ] +} +``` + +## Storage +Per-agent DB (default): `~/.clawdbot/memory/{agentId}.sqlite`. + +Tables (v1): +- `files(path PRIMARY KEY, hash, mtime, size)` +- `chunks(id PRIMARY KEY, path, start_line, end_line, hash, text, embedding, updated_at)` + +Notes: +- `hash` = content hash of chunk text. +- `embedding` stored as float[] (sqlite vec extension optional); if not using vec, + store as JSON and do linear scan in memory for small corpora. + +## Embedding Providers +Interface (core): +- `embedQuery(text): number[]` +- `embedBatch(texts[]): number[][]` + +Providers: +- `openai` (default): OpenAI embeddings via existing keys. +- `local` (optional): node-llama-cpp (GGUF). +- Fallback: when `provider: "local"` fails, fallback to OpenAI unless `fallback: "none"`. + +## Index Pipeline +1) Resolve memory file list (workspace only). +2) Read file, compute file hash/mtime. +3) Chunk by headings + token cap (overlap). +4) Embed only changed chunks (hash compare). +5) Upsert `chunks` rows, prune deleted files. + +Chunking: +- Prefer heading-aware splits. +- Max tokens + overlap; keep line ranges for snippets. + +## Sync Strategy +Default: **watch + lazy + session-start** +- `watch`: chokidar on `MEMORY.md` + `memory/**/*.md` (debounced). +- `onSearch`: if dirty, sync before search (LazySync). +- `onSessionStart`: warm index once per session. +- `intervalMinutes`: optional for long-lived sessions. + +If workspace access is read-only or missing: disable writes; return “not indexed”. + +## Query Flow +1) Embed query. +2) Cosine similarity over all chunk embeddings. +3) Return top K with `{path, startLine, endLine, snippet, score}`. +4) Model may call `memory_get` when full context needed. + +Optional v2: add FTS5 + RRF merge (FTS + vector) for quality. + +## Tool + CLI +Tools: +- `memory_search { query, maxResults?, minScore? }` +- `memory_get { path, from?, lines? }` + +CLI (optional): +- `clawdbot memory index|search|status` + +## Security + Permissions +- Indexer reads only memory files in workspace. +- No scanning outside workspace; no “sneak” reads. +- Respect sandbox `workspaceAccess` (ro = read-only; none = disabled). + +## Tests +- Chunking boundaries + line ranges. +- Hash-based incremental updates. +- Search ranking (cosine). +- Watcher debounce (fake fs). + +## Rollout +- Default enabled; if no memory files, index is empty (silent). +- No migration needed. diff --git a/package.json b/package.json index 663f1f36b..b36df1408 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "json5": "^2.2.3", "long": "5.3.2", "markdown-it": "^14.1.0", + "node-llama-cpp": "3.14.5", "osc-progress": "^0.2.0", "playwright-core": "1.57.0", "proper-lockfile": "^4.1.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0089c1b6d..4b7d06a7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -115,6 +115,9 @@ importers: markdown-it: specifier: ^14.1.0 version: 14.1.0 + node-llama-cpp: + specifier: 3.14.5 + version: 3.14.5(typescript@5.9.3) osc-progress: specifier: ^0.2.0 version: 0.2.0 @@ -609,6 +612,10 @@ packages: peerDependencies: hono: ^4 + '@huggingface/jinja@0.5.3': + resolution: {integrity: sha512-asqfZ4GQS0hD876Uw4qiUb7Tr/V5Q+JZuo2L+BtdrD4U40QU58nIRq3ZSgAzJgT874VLjhGVacaYfrdpXtEvtA==} + engines: {node: '>=18'} + '@img/colour@1.0.0': resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} engines: {node: '>=18'} @@ -781,6 +788,12 @@ packages: '@keyv/serialize@1.1.1': resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + '@kwsites/file-exists@1.1.1': + resolution: {integrity: sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==} + + '@kwsites/promise-deferred@1.1.1': + resolution: {integrity: sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==} + '@lit-labs/signals@0.2.0': resolution: {integrity: sha512-68plyIbciumbwKaiilhLNyhz4Vg6/+nJwDufG2xxWA9r/fUw58jxLHCAlKs+q1CE5Lmh3cZ3ShyYKnOCebEpVA==} @@ -895,6 +908,84 @@ packages: '@napi-rs/wasm-runtime@1.1.1': resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} + '@node-llama-cpp/linux-arm64@3.14.5': + resolution: {integrity: sha512-58IcWW7EOqc/66mYWXRsoMCy1MR3pTX/YaC0HYF9Rg5XeAPKhUP7NHrglbqgjO62CkcuFZaSEiX2AtG972GQYQ==} + engines: {node: '>=20.0.0'} + cpu: [arm64, x64] + os: [linux] + + '@node-llama-cpp/linux-armv7l@3.14.5': + resolution: {integrity: sha512-mJWN0qWsn8y+r/34DC3XlSiXjjKs6wX1BTx0wwJ37fWefS/qfzuBJwQGqpfqe5xpfafib/RgQX44fsvE/9yb1w==} + engines: {node: '>=20.0.0'} + cpu: [arm, x64] + os: [linux] + + '@node-llama-cpp/linux-x64-cuda-ext@3.14.5': + resolution: {integrity: sha512-AACXmXjqvAppoC6Z20UI7yeSZaFb6uP9x/2lzctVwlm42ef76SN6DNXaX1yzH7DTyzK5zYhoH4ycJUe+zOeGzw==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [linux] + + '@node-llama-cpp/linux-x64-cuda@3.14.5': + resolution: {integrity: sha512-yk0EGnAJ+m/paSaItigmxcqC8nNjZlkx9yZgQE51CsTip7tmnqqlj60pW1fWmhrjOJ9XnRlVVTP81fa9B+O1Hg==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [linux] + + '@node-llama-cpp/linux-x64-vulkan@3.14.5': + resolution: {integrity: sha512-9wZG90CUyyO8EsqfDEh03/fK0ctbQFbKaAFa6Goh+jFLOtqPL+plLqAsW3jDFdLRF5+oAPTKt9/4Y7vHTajQbQ==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [linux] + + '@node-llama-cpp/linux-x64@3.14.5': + resolution: {integrity: sha512-f6xCqlSqSxMP9Iwm3CpaTzFybbHrzpLkNzA18v21PwhMN8u4DP44euLoxe+BMbOpyzx4iMxU1AUsPsgcHD1Y4w==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [linux] + + '@node-llama-cpp/mac-arm64-metal@3.14.5': + resolution: {integrity: sha512-7pclj/nbQyx7gPVbyqkCn+ftlGcnw7YrewxBv1/BWWAMzBrMt2+qkjtUcUhwXH7mT5WN/+eWsszhIMXH3Uf6vQ==} + engines: {node: '>=20.0.0'} + cpu: [arm64, x64] + os: [darwin] + + '@node-llama-cpp/mac-x64@3.14.5': + resolution: {integrity: sha512-iZBmLgPkLKiKS0lYAuqq8i85etGeQ9L+AjEJUhG5N6T/vCF4XSOkUTsEFMEX+iJLV3VxvY/C8R1e/UF7InUjUg==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [darwin] + + '@node-llama-cpp/win-arm64@3.14.5': + resolution: {integrity: sha512-WTZJeb2JZo/qPNHf++xA2YeMXB46G7G4WsKEnHVyCpAhhslHAhe/LPgSQfNfk9rYusbsRiy9QMxeGNSOowZMVQ==} + engines: {node: '>=20.0.0'} + cpu: [arm64, x64] + os: [win32] + + '@node-llama-cpp/win-x64-cuda-ext@3.14.5': + resolution: {integrity: sha512-kBHnUmodr+n8N+sKTh1c6aNNEmvXBWM5AtaLWIEfkCb00bVHNFeqYPmLuPNtMX3dIUtD9PHdA4Jsn0RJmNZJfA==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [win32] + + '@node-llama-cpp/win-x64-cuda@3.14.5': + resolution: {integrity: sha512-gwBMSzUteLD765Gq/hYQ4UC21vggR7oG+DU4zAg0Mt3i34PqKJC+tBop5jsTN5Hq8RaM9+nTNrVbF/x228TLvg==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [win32] + + '@node-llama-cpp/win-x64-vulkan@3.14.5': + resolution: {integrity: sha512-rY+vr5RaGSCWEe22WZMkhUu16o9zpeqTZO/nD5G27Y0bb+xBRDLmXbxYMp2dDQTfpkNWIZ0ia3PGWwl5yhYw7A==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [win32] + + '@node-llama-cpp/win-x64@3.14.5': + resolution: {integrity: sha512-cEuhb1iLTodM+V8xc1mWKeWRYkX9tlnl0+9jUjwsv2kgnAjEob3WlTYsCXewvEe2ShSyk8AsLsBPZxv7IQaBsw==} + engines: {node: '>=20.0.0'} + cpu: [x64] + os: [win32] + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -907,6 +998,113 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} + '@octokit/app@16.1.2': + resolution: {integrity: sha512-8j7sEpUYVj18dxvh0KWj6W/l6uAiVRBl1JBDVRqH1VHKAO/G5eRVl4yEoYACjakWers1DjUkcCHyJNQK47JqyQ==} + engines: {node: '>= 20'} + + '@octokit/auth-app@8.1.2': + resolution: {integrity: sha512-db8VO0PqXxfzI6GdjtgEFHY9tzqUql5xMFXYA12juq8TeTgPAuiiP3zid4h50lwlIP457p5+56PnJOgd2GGBuw==} + engines: {node: '>= 20'} + + '@octokit/auth-oauth-app@9.0.3': + resolution: {integrity: sha512-+yoFQquaF8OxJSxTb7rnytBIC2ZLbLqA/yb71I4ZXT9+Slw4TziV9j/kyGhUFRRTF2+7WlnIWsePZCWHs+OGjg==} + engines: {node: '>= 20'} + + '@octokit/auth-oauth-device@8.0.3': + resolution: {integrity: sha512-zh2W0mKKMh/VWZhSqlaCzY7qFyrgd9oTWmTmHaXnHNeQRCZr/CXy2jCgHo4e4dJVTiuxP5dLa0YM5p5QVhJHbw==} + engines: {node: '>= 20'} + + '@octokit/auth-oauth-user@6.0.2': + resolution: {integrity: sha512-qLoPPc6E6GJoz3XeDG/pnDhJpTkODTGG4kY0/Py154i/I003O9NazkrwJwRuzgCalhzyIeWQ+6MDvkUmKXjg/A==} + engines: {node: '>= 20'} + + '@octokit/auth-token@6.0.0': + resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} + engines: {node: '>= 20'} + + '@octokit/auth-unauthenticated@7.0.3': + resolution: {integrity: sha512-8Jb1mtUdmBHL7lGmop9mU9ArMRUTRhg8vp0T1VtZ4yd9vEm3zcLwmjQkhNEduKawOOORie61xhtYIhTDN+ZQ3g==} + engines: {node: '>= 20'} + + '@octokit/core@7.0.6': + resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==} + engines: {node: '>= 20'} + + '@octokit/endpoint@11.0.2': + resolution: {integrity: sha512-4zCpzP1fWc7QlqunZ5bSEjxc6yLAlRTnDwKtgXfcI/FxxGoqedDG8V2+xJ60bV2kODqcGB+nATdtap/XYq2NZQ==} + engines: {node: '>= 20'} + + '@octokit/graphql@9.0.3': + resolution: {integrity: sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==} + engines: {node: '>= 20'} + + '@octokit/oauth-app@8.0.3': + resolution: {integrity: sha512-jnAjvTsPepyUaMu9e69hYBuozEPgYqP4Z3UnpmvoIzHDpf8EXDGvTY1l1jK0RsZ194oRd+k6Hm13oRU8EoDFwg==} + engines: {node: '>= 20'} + + '@octokit/oauth-authorization-url@8.0.0': + resolution: {integrity: sha512-7QoLPRh/ssEA/HuHBHdVdSgF8xNLz/Bc5m9fZkArJE5bb6NmVkDm3anKxXPmN1zh6b5WKZPRr3697xKT/yM3qQ==} + engines: {node: '>= 20'} + + '@octokit/oauth-methods@6.0.2': + resolution: {integrity: sha512-HiNOO3MqLxlt5Da5bZbLV8Zarnphi4y9XehrbaFMkcoJ+FL7sMxH/UlUsCVxpddVu4qvNDrBdaTVE2o4ITK8ng==} + engines: {node: '>= 20'} + + '@octokit/openapi-types@27.0.0': + resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==} + + '@octokit/openapi-webhooks-types@12.1.0': + resolution: {integrity: sha512-WiuzhOsiOvb7W3Pvmhf8d2C6qaLHXrWiLBP4nJ/4kydu+wpagV5Fkz9RfQwV2afYzv3PB+3xYgp4mAdNGjDprA==} + + '@octokit/plugin-paginate-graphql@6.0.0': + resolution: {integrity: sha512-crfpnIoFiBtRkvPqOyLOsw12XsveYuY2ieP6uYDosoUegBJpSVxGwut9sxUgFFcll3VTOTqpUf8yGd8x1OmAkQ==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-paginate-rest@14.0.0': + resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-rest-endpoint-methods@17.0.0': + resolution: {integrity: sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=6' + + '@octokit/plugin-retry@8.0.3': + resolution: {integrity: sha512-vKGx1i3MC0za53IzYBSBXcrhmd+daQDzuZfYDd52X5S0M2otf3kVZTVP8bLA3EkU0lTvd1WEC2OlNNa4G+dohA==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': '>=7' + + '@octokit/plugin-throttling@11.0.3': + resolution: {integrity: sha512-34eE0RkFCKycLl2D2kq7W+LovheM/ex3AwZCYN8udpi6bxsyjZidb2McXs69hZhLmJlDqTSP8cH+jSRpiaijBg==} + engines: {node: '>= 20'} + peerDependencies: + '@octokit/core': ^7.0.0 + + '@octokit/request-error@7.1.0': + resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} + engines: {node: '>= 20'} + + '@octokit/request@10.0.7': + resolution: {integrity: sha512-v93h0i1yu4idj8qFPZwjehoJx4j3Ntn+JhXsdJrG9pYaX6j/XRz2RmasMUHtNgQD39nrv/VwTWSqK0RNXR8upA==} + engines: {node: '>= 20'} + + '@octokit/types@16.0.0': + resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} + + '@octokit/webhooks-methods@6.0.0': + resolution: {integrity: sha512-MFlzzoDJVw/GcbfzVC1RLR36QqkTLUf79vLVO3D+xn7r0QgxnFoLZgtrzxiQErAjFUOdH6fas2KeQJ1yr/qaXQ==} + engines: {node: '>= 20'} + + '@octokit/webhooks@14.2.0': + resolution: {integrity: sha512-da6KbdNCV5sr1/txD896V+6W0iamFWrvVl8cHkBSPT+YlvmT3DwXa4jxZnQc+gnuTEqSWbBeoSZYTayXH9wXcw==} + engines: {node: '>= 20'} + '@oxc-project/types@0.107.0': resolution: {integrity: sha512-QFDRbYfV2LVx8tyqtyiah3jQPUj1mK2+RYwxyFWyGoys6XJnwTdlzO6rdNNHOPorHAu5Uo34oWRKcvNpbJarmQ==} @@ -1023,6 +1221,58 @@ packages: '@protobufjs/utf8@1.1.0': resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + '@reflink/reflink-darwin-arm64@0.1.19': + resolution: {integrity: sha512-ruy44Lpepdk1FqDz38vExBY/PVUsjxZA+chd9wozjUH9JjuDT/HEaQYA6wYN9mf041l0yLVar6BCZuWABJvHSA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@reflink/reflink-darwin-x64@0.1.19': + resolution: {integrity: sha512-By85MSWrMZa+c26TcnAy8SDk0sTUkYlNnwknSchkhHpGXOtjNDUOxJE9oByBnGbeuIE1PiQsxDG3Ud+IVV9yuA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@reflink/reflink-linux-arm64-gnu@0.1.19': + resolution: {integrity: sha512-7P+er8+rP9iNeN+bfmccM4hTAaLP6PQJPKWSA4iSk2bNvo6KU6RyPgYeHxXmzNKzPVRcypZQTpFgstHam6maVg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@reflink/reflink-linux-arm64-musl@0.1.19': + resolution: {integrity: sha512-37iO/Dp6m5DDaC2sf3zPtx/hl9FV3Xze4xoYidrxxS9bgP3S8ALroxRK6xBG/1TtfXKTvolvp+IjrUU6ujIGmA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@reflink/reflink-linux-x64-gnu@0.1.19': + resolution: {integrity: sha512-jbI8jvuYCaA3MVUdu8vLoLAFqC+iNMpiSuLbxlAgg7x3K5bsS8nOpTRnkLF7vISJ+rVR8W+7ThXlXlUQ93ulkw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@reflink/reflink-linux-x64-musl@0.1.19': + resolution: {integrity: sha512-e9FBWDe+lv7QKAwtKOt6A2W/fyy/aEEfr0g6j/hWzvQcrzHCsz07BNQYlNOjTfeytrtLU7k449H1PI95jA4OjQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@reflink/reflink-win32-arm64-msvc@0.1.19': + resolution: {integrity: sha512-09PxnVIQcd+UOn4WAW73WU6PXL7DwGS6wPlkMhMg2zlHHG65F3vHepOw06HFCq+N42qkaNAc8AKIabWvtk6cIQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@reflink/reflink-win32-x64-msvc@0.1.19': + resolution: {integrity: sha512-E//yT4ni2SyhwP8JRjVGWr3cbnhWDiPLgnQ66qqaanjjnMiu3O/2tjCPQXlcGc/DEYofpDc9fvhv6tALQsMV9w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@reflink/reflink@0.1.19': + resolution: {integrity: sha512-DmCG8GzysnCZ15bres3N5AHCmwBwYgp0As6xjhQ47rAUTUXxJiK+lLUxaGsX3hd/30qUpVElh05PbGuxRPgJwA==} + engines: {node: '>= 10'} + '@rolldown/binding-android-arm64@1.0.0-beta.59': resolution: {integrity: sha512-6yLLgyswYwiCfls9+hoNFY9F8TQdwo15hpXDHzlAR0X/GojeKF+AuNcXjYNbOJ4zjl/5D6lliE8CbpB5t1OWIQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -1278,6 +1528,10 @@ packages: resolution: {integrity: sha512-wBfSWz81sqM1FWX2ucW9KGLSFzGvsBxwX5y5t6Oty0QWO9mY8JIZC+ZBPzX5E6ExZiuGIgM8NtkTboTnXXlfUQ==} engines: {node: '>=18'} + '@tinyhttp/content-disposition@2.2.2': + resolution: {integrity: sha512-crXw1txzrS36huQOyQGYFvhTeLeG0Si1xu+/l6kXUVYpE0TjFjEZRqTbuadQLfKGZ0jaI+jJoRyqaWwxOSHW2g==} + engines: {node: '>=12.20.0'} + '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} @@ -1291,6 +1545,9 @@ packages: '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + '@types/aws-lambda@8.10.159': + resolution: {integrity: sha512-SAP22WSGNN12OQ8PlCzGzRCZ7QDCwI85dQZbmpz7+mAk+L7j+wI7qnvmdKh+o7A5LaOp6QnOZ2NJphAZQTTHQg==} + '@types/body-parser@1.19.6': resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} @@ -1512,6 +1769,10 @@ packages: alien-signals@2.0.8: resolution: {integrity: sha512-844G1VLkk0Pe2SJjY0J8vp8ADI73IM4KliNu2OGlYzWpO28NexEUvjHTcFjFX3VXoiUtwTbHxLNI9ImkcoBqzA==} + ansi-escapes@6.2.1: + resolution: {integrity: sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==} + engines: {node: '>=14.16'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1539,6 +1800,14 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + aproba@2.1.0: + resolution: {integrity: sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==} + + are-we-there-yet@3.0.1: + resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} @@ -1555,6 +1824,9 @@ packages: async-mutex@0.5.0: resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1585,6 +1857,9 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + before-after-hook@4.0.0: + resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} @@ -1652,6 +1927,9 @@ packages: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chmodrp@1.0.2: + resolution: {integrity: sha512-TdngOlFV1FLTzU0o1w8MB6/BFywhtLC0SzRTGJU7T9lmdjlCWeMRt1iVo0Ki+ldwNk0BqNiKoc8xpLZEQ8mY1w==} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -1660,6 +1938,10 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + chownr@3.0.0: resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} engines: {node: '>=18'} @@ -1669,21 +1951,42 @@ packages: peerDependencies: devtools-protocol: '*' + ci-info@4.3.1: + resolution: {integrity: sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==} + engines: {node: '>=8'} + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + cli-highlight@2.1.11: resolution: {integrity: sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==} engines: {node: '>=8.0.0', npm: '>=5.0.0'} hasBin: true + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + cmake-js@7.4.0: + resolution: {integrity: sha512-Lw0JxEHrmk+qNj1n9W9d4IvkDdYTBn7l2BW6XmtLj7WPpIo2shvxUy+YokfjMxAAOELNonQwX3stkPhM5xSC2Q==} + engines: {node: '>= 14.15.0'} + hasBin: true + codec-parser@2.5.0: resolution: {integrity: sha512-Ru9t80fV8B0ZiixQl8xhMTLru+dzuis/KQld32/x5T/+3LwZb0/YvQdSKytX9JqCnRdiupvAvyYJINKrXieziQ==} @@ -1697,10 +2000,18 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + commander@14.0.2: resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} engines: {node: '>=20'} @@ -1709,6 +2020,9 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} @@ -1755,10 +2069,17 @@ packages: supports-color: optional: true + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} @@ -1810,6 +2131,9 @@ packages: ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1824,6 +2148,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + env-var@7.5.0: + resolution: {integrity: sha512-mKZOzLRN0ETzau2W2QXefbFjo5EF4yWq28OyKb9ICdeNhHJlOE/pHHnz4hdYJ9cNZXcJHo5xN4OT4pzuSHSNvA==} + engines: {node: '>=10'} + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} @@ -1887,6 +2215,9 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + fast-content-type-parse@3.0.0: + resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1917,6 +2248,14 @@ packages: resolution: {integrity: sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA==} engines: {node: '>=20'} + filename-reserved-regex@3.0.0: + resolution: {integrity: sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + filenamify@6.0.0: + resolution: {integrity: sha512-vqIlNogKeyD3yzrm0yhRMQg8hOVwYcYRfjEoODd49iCprMn4HL85gK3HcykQE53EPIpX3HcAbGA5ELQv216dAQ==} + engines: {node: '>=16'} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1954,6 +2293,14 @@ packages: resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} engines: {node: '>= 0.8'} + fs-extra@11.3.3: + resolution: {integrity: sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==} + engines: {node: '>=14.14'} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1967,6 +2314,11 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + gauge@4.0.4: + resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. + gaxios@7.1.3: resolution: {integrity: sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==} engines: {node: '>=18'} @@ -2042,6 +2394,9 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + hashery@1.4.0: resolution: {integrity: sha512-Wn2i1In6XFxl8Az55kkgnFRiAlIAushzh26PTjL2AKtQcEfXrcLa7Hn5QOWGZEf3LU057P9TwwZjFyxfS1VuvQ==} engines: {node: '>=20'} @@ -2089,16 +2444,28 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + ipull@3.9.3: + resolution: {integrity: sha512-ZMkxaopfwKHwmEuGDYx7giNBdLxbHbRCWcQVA1D2eqE4crUguupfxej6s7UqbidYEwT69dkyumYkY8DPHIxF9g==} + engines: {node: '>=18.0.0'} + hasBin: true + is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -2114,10 +2481,18 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-interactive@2.0.0: + resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} + engines: {node: '>=12'} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -2129,6 +2504,14 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + + is-unicode-supported@2.1.0: + resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} + engines: {node: '>=18'} + is-url@1.2.4: resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} @@ -2138,6 +2521,10 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.1: + resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} + engines: {node: '>=16'} + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -2195,6 +2582,9 @@ packages: jsonc-parser@3.3.1: resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonwebtoken@9.0.3: resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} engines: {node: '>=12', npm: '>=6'} @@ -2222,6 +2612,12 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lifecycle-utils@2.1.0: + resolution: {integrity: sha512-AnrXnE2/OF9PHCyFg0RSqsnQTzV991XaZA/buhFDoc58xU7rhSCDgCz/09Lqpsn4MpoPHt7TRAXV1kWZypFVsA==} + + lifecycle-utils@3.0.1: + resolution: {integrity: sha512-Qt/Jl5dsNIsyCAZsHB6x3mbwHFn0HJbdmvF49sVX/bHgX2cW7+G+U+I67Zw+TPM1Sr21Gb2nfJMd2g6iUcI1EQ==} + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} @@ -2310,6 +2706,9 @@ packages: lodash.clonedeep@4.5.0: resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==} + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + lodash.includes@4.3.0: resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} @@ -2334,12 +2733,24 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + log-symbols@6.0.0: + resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} + engines: {node: '>=18'} + + log-symbols@7.0.1: + resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} + engines: {node: '>=18'} + long@4.0.0: resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} long@5.3.2: resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + lowdb@7.0.1: + resolution: {integrity: sha512-neJAj8GwF0e8EpycYIDFqEPcx9Qz4GUho20jWFR7YiFeXzF1YMLdxB36PypcTSPMA+4+LvgyMacYhlr18Zlymw==} + engines: {node: '>=18'} + lru-cache@10.4.3: resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} @@ -2404,6 +2815,9 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + memory-stream@1.0.0: + resolution: {integrity: sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww==} + merge-descriptors@2.0.0: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} @@ -2432,6 +2846,10 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + minimatch@10.1.1: resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} engines: {node: 20 || >=22} @@ -2440,10 +2858,25 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + minipass@7.1.2: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + minizlib@3.1.0: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} @@ -2451,6 +2884,11 @@ packages: mitt@3.0.1: resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + mpg123-decoder@1.0.3: resolution: {integrity: sha512-+fjxnWigodWJm3+4pndi+KUg9TBojgn31DPk85zEsim7C6s0X5Ztc/hQYdytXkwuGXH+aB0/aEkG40Emukv6oQ==} @@ -2473,10 +2911,22 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanoid@5.1.6: + resolution: {integrity: sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==} + engines: {node: ^18 || >=20} + hasBin: true + negotiator@1.0.0: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + node-addon-api@8.5.0: + resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} + engines: {node: ^18 || ^20 || >= 21} + + node-api-headers@1.7.0: + resolution: {integrity: sha512-uJMGdkhVwu9+I3UsVvI3KW6ICAy/yDfsu5Br9rSnTtY3WpoaComXvKloiV5wtx0Md2rn0B9n29Ys2WMNwWxj9A==} + node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -2495,6 +2945,16 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-llama-cpp@3.14.5: + resolution: {integrity: sha512-Db+RFqFMJOOVWprUINq77LVe44FaiJ6JvNiq14r2+DZRgkgyxckSZa6DcZ5Xe5MC+hGA5aqOdnNxsrudUcs74Q==} + engines: {node: '>=20.0.0'} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + peerDependenciesMeta: + typescript: + optional: true + node-wav@0.0.2: resolution: {integrity: sha512-M6Rm/bbG6De/gKGxOpeOobx/dnGuP0dz40adqx38boqHhlWssBJZgLCPBNtb9NkrmnKYiV04xELq+R6PFOnoLA==} engines: {node: '>=4.4.0'} @@ -2503,6 +2963,11 @@ packages: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} + npmlog@6.0.2: + resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2518,6 +2983,10 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + octokit@5.0.5: + resolution: {integrity: sha512-4+/OFSqOjoyULo7eN7EA97DE0Xydj/PW5aIckxqQIoFjFwqXKuFCvXUJObyJfBF9Khu4RL/jlDRI9FPaMGfPnw==} + engines: {node: '>= 20'} + ogg-opus-decoder@1.7.3: resolution: {integrity: sha512-w47tiZpkLgdkpa+34VzYD8mHUj8I9kfWVZa82mBbNwDvB1byfLXSSzW/HxA4fI3e9kVlICSpXGFwMLV1LPdjwg==} @@ -2535,6 +3004,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + openai@6.10.0: resolution: {integrity: sha512-ITxOGo7rO3XRMiKA5l7tQ43iNNu+iXGFAcf2t+aWVzzqRaS0i7m1K2BhxNdaveB+5eENhO0VY1FkiZzhBk4v3A==} hasBin: true @@ -2550,6 +3023,10 @@ packages: opus-decoder@0.7.11: resolution: {integrity: sha512-+e+Jz3vGQLxRTBHs8YJQPRPc1Tr+/aC6coV/DlZylriA29BdHQAYXhvNRKtjftof17OFng0+P4wsFIqQu3a48A==} + ora@8.2.0: + resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} + engines: {node: '>=18'} + osc-progress@0.2.0: resolution: {integrity: sha512-GJR9XnS8dQ+sAdbhX90RA4WbmEyrso7X9aHMws4MaQ2GRpfEjnOUSZIdOXJQfnIfBoy9oCc7US/MNFCyuJQzjg==} engines: {node: '>=20'} @@ -2601,6 +3078,14 @@ packages: pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parse-ms@3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} + + parse-ms@4.0.0: + resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} + engines: {node: '>=18'} + parse5-htmlparser2-tree-adapter@6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} @@ -2682,10 +3167,22 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + pretty-bytes@6.1.1: + resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} + engines: {node: ^14.13.1 || >=16.0.0} + pretty-format@27.5.1: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + pretty-ms@8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} + + pretty-ms@9.3.0: + resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + engines: {node: '>=18'} + prism-media@1.3.5: resolution: {integrity: sha512-IQdl0Q01m4LrkN1EGIE9lphov5Hy7WWlH6ulf5QdGePLlPas9p2mhgddTEHrlaXYjjFToM1/rWuwF37VF4taaA==} peerDependencies: @@ -2767,12 +3264,20 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + readable-stream@4.5.2: resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2800,6 +3305,10 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + retry@0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -2859,6 +3368,9 @@ packages: resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -2911,6 +3423,9 @@ packages: peerDependencies: signal-polyfill: ^0.2.0 + simple-git@3.30.0: + resolution: {integrity: sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==} + simple-yenc@1.0.4: resolution: {integrity: sha512-5gvxpSd79e9a3V4QDYUqnqxeD4HGlhCakVpb6gMnDD7lexJggSBJRBO5h52y/iJrdXRilX9UCuDaIJhSWm5OWw==} @@ -2921,6 +3436,13 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + sleep-promise@9.1.0: + resolution: {integrity: sha512-UHYzVpz9Xn8b+jikYSD6bqvf754xL2uBUzDFwiU6NcdZeifPr6UfgU43xpkPu67VMS88+TI2PSI7Eohgqf2fKA==} + + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + sonic-boom@4.2.0: resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==} @@ -2949,6 +3471,18 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + stdin-discarder@0.2.2: + resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} + engines: {node: '>=18'} + + stdout-update@4.0.1: + resolution: {integrity: sha512-wiS21Jthlvl1to+oorePvcyrIkiG/6M3D3VTmDUlJm7Cy6SbFhKkAvX+YBuHLxck/tO3mrdpC/cNesigQc3+UQ==} + engines: {node: '>=16.0.0'} + + steno@4.0.2: + resolution: {integrity: sha512-yhPIQXjrlt1xv7dyPQg2P17URmXbuM5pdGkpiMB3RenprfiBlvK415Lctfe0eshk90oA7/tNq7WEiMK8RSP39A==} + engines: {node: '>=18'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -2957,6 +3491,10 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -2971,6 +3509,10 @@ packages: resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} engines: {node: '>=12'} + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + strtok3@10.3.4: resolution: {integrity: sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg==} engines: {node: '>=18'} @@ -2995,6 +3537,10 @@ packages: tailwindcss@4.1.17: resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + tar@7.5.2: resolution: {integrity: sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==} engines: {node: '>=18'} @@ -3031,6 +3577,10 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toad-cache@3.7.0: + resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} + engines: {node: '>=12'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} @@ -3097,6 +3647,16 @@ packages: unicode-trie@2.0.0: resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + universal-github-app-jwt@2.2.2: + resolution: {integrity: sha512-dcmbeSrOdTnsjGjUfAlqNDJrhxXizjAz94ija9Qw8YkZ1uu0d+GoZzyH+Jb9tIIqvGsadUfwg+22k5aDqqwzbw==} + + universal-user-agent@7.0.3: + resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -3104,6 +3664,9 @@ packages: urijs@1.19.11: resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} + url-join@4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -3115,6 +3678,10 @@ packages: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true + validate-npm-package-name@6.0.2: + resolution: {integrity: sha512-IUoow1YUtvoBBC06dXs8bR8B9vuA3aJfmQNKMoaPG/OFsPmoQvw8xh+6Ye25Gx9DQhoEom3Pcu9MKHerm/NpUQ==} + engines: {node: ^18.17.0 || >=20.5.0} + vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -3211,11 +3778,19 @@ packages: engines: {node: '>= 8'} hasBin: true + which@5.0.0: + resolution: {integrity: sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true + wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + wireit@0.14.12: resolution: {integrity: sha512-gNSd+nZmMo6cuICezYXRIayu6TSOeCSCDzjSF0q6g8FKDsRbdqrONrSZYzdk/uBISmRcv4vZtsno6GyGvdXwGA==} engines: {node: '>=18.0.0'} @@ -3279,10 +3854,22 @@ packages: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + yargs@16.2.0: resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} engines: {node: '>=10'} + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yoctocolors@2.1.2: + resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + engines: {node: '>=18'} + zod-to-json-schema@3.25.1: resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} peerDependencies: @@ -3602,6 +4189,8 @@ snapshots: hono: 4.11.3 optional: true + '@huggingface/jinja@0.5.3': {} + '@img/colour@1.0.0': {} '@img/sharp-darwin-arm64@0.34.5': @@ -3734,6 +4323,14 @@ snapshots: '@keyv/serialize@1.1.1': {} + '@kwsites/file-exists@1.1.1': + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@kwsites/promise-deferred@1.1.1': {} + '@lit-labs/signals@0.2.0': dependencies: lit: 3.3.2 @@ -3897,7 +4494,7 @@ snapshots: '@azure/core-auth': 1.10.1 '@azure/msal-node': 3.8.4 '@microsoft/agents-activity': 1.1.1 - axios: 1.13.2 + axios: 1.13.2(debug@4.4.3) jsonwebtoken: 9.0.3 jwks-rsa: 3.2.0 object-path: 0.11.8 @@ -3917,6 +4514,45 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true + '@node-llama-cpp/linux-arm64@3.14.5': + optional: true + + '@node-llama-cpp/linux-armv7l@3.14.5': + optional: true + + '@node-llama-cpp/linux-x64-cuda-ext@3.14.5': + optional: true + + '@node-llama-cpp/linux-x64-cuda@3.14.5': + optional: true + + '@node-llama-cpp/linux-x64-vulkan@3.14.5': + optional: true + + '@node-llama-cpp/linux-x64@3.14.5': + optional: true + + '@node-llama-cpp/mac-arm64-metal@3.14.5': + optional: true + + '@node-llama-cpp/mac-x64@3.14.5': + optional: true + + '@node-llama-cpp/win-arm64@3.14.5': + optional: true + + '@node-llama-cpp/win-x64-cuda-ext@3.14.5': + optional: true + + '@node-llama-cpp/win-x64-cuda@3.14.5': + optional: true + + '@node-llama-cpp/win-x64-vulkan@3.14.5': + optional: true + + '@node-llama-cpp/win-x64@3.14.5': + optional: true + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -3929,6 +4565,153 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.20.1 + '@octokit/app@16.1.2': + dependencies: + '@octokit/auth-app': 8.1.2 + '@octokit/auth-unauthenticated': 7.0.3 + '@octokit/core': 7.0.6 + '@octokit/oauth-app': 8.0.3 + '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) + '@octokit/types': 16.0.0 + '@octokit/webhooks': 14.2.0 + + '@octokit/auth-app@8.1.2': + dependencies: + '@octokit/auth-oauth-app': 9.0.3 + '@octokit/auth-oauth-user': 6.0.2 + '@octokit/request': 10.0.7 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + toad-cache: 3.7.0 + universal-github-app-jwt: 2.2.2 + universal-user-agent: 7.0.3 + + '@octokit/auth-oauth-app@9.0.3': + dependencies: + '@octokit/auth-oauth-device': 8.0.3 + '@octokit/auth-oauth-user': 6.0.2 + '@octokit/request': 10.0.7 + '@octokit/types': 16.0.0 + universal-user-agent: 7.0.3 + + '@octokit/auth-oauth-device@8.0.3': + dependencies: + '@octokit/oauth-methods': 6.0.2 + '@octokit/request': 10.0.7 + '@octokit/types': 16.0.0 + universal-user-agent: 7.0.3 + + '@octokit/auth-oauth-user@6.0.2': + dependencies: + '@octokit/auth-oauth-device': 8.0.3 + '@octokit/oauth-methods': 6.0.2 + '@octokit/request': 10.0.7 + '@octokit/types': 16.0.0 + universal-user-agent: 7.0.3 + + '@octokit/auth-token@6.0.0': {} + + '@octokit/auth-unauthenticated@7.0.3': + dependencies: + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + + '@octokit/core@7.0.6': + dependencies: + '@octokit/auth-token': 6.0.0 + '@octokit/graphql': 9.0.3 + '@octokit/request': 10.0.7 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + before-after-hook: 4.0.0 + universal-user-agent: 7.0.3 + + '@octokit/endpoint@11.0.2': + dependencies: + '@octokit/types': 16.0.0 + universal-user-agent: 7.0.3 + + '@octokit/graphql@9.0.3': + dependencies: + '@octokit/request': 10.0.7 + '@octokit/types': 16.0.0 + universal-user-agent: 7.0.3 + + '@octokit/oauth-app@8.0.3': + dependencies: + '@octokit/auth-oauth-app': 9.0.3 + '@octokit/auth-oauth-user': 6.0.2 + '@octokit/auth-unauthenticated': 7.0.3 + '@octokit/core': 7.0.6 + '@octokit/oauth-authorization-url': 8.0.0 + '@octokit/oauth-methods': 6.0.2 + '@types/aws-lambda': 8.10.159 + universal-user-agent: 7.0.3 + + '@octokit/oauth-authorization-url@8.0.0': {} + + '@octokit/oauth-methods@6.0.2': + dependencies: + '@octokit/oauth-authorization-url': 8.0.0 + '@octokit/request': 10.0.7 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + + '@octokit/openapi-types@27.0.0': {} + + '@octokit/openapi-webhooks-types@12.1.0': {} + + '@octokit/plugin-paginate-graphql@6.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + + '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 + + '@octokit/plugin-rest-endpoint-methods@17.0.0(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 + + '@octokit/plugin-retry@8.0.3(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + bottleneck: 2.19.5 + + '@octokit/plugin-throttling@11.0.3(@octokit/core@7.0.6)': + dependencies: + '@octokit/core': 7.0.6 + '@octokit/types': 16.0.0 + bottleneck: 2.19.5 + + '@octokit/request-error@7.1.0': + dependencies: + '@octokit/types': 16.0.0 + + '@octokit/request@10.0.7': + dependencies: + '@octokit/endpoint': 11.0.2 + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + fast-content-type-parse: 3.0.0 + universal-user-agent: 7.0.3 + + '@octokit/types@16.0.0': + dependencies: + '@octokit/openapi-types': 27.0.0 + + '@octokit/webhooks-methods@6.0.0': {} + + '@octokit/webhooks@14.2.0': + dependencies: + '@octokit/openapi-webhooks-types': 12.1.0 + '@octokit/request-error': 7.1.0 + '@octokit/webhooks-methods': 6.0.0 + '@oxc-project/types@0.107.0': {} '@oxlint-tsgolint/darwin-arm64@0.11.0': @@ -4005,6 +4788,42 @@ snapshots: '@protobufjs/utf8@1.1.0': {} + '@reflink/reflink-darwin-arm64@0.1.19': + optional: true + + '@reflink/reflink-darwin-x64@0.1.19': + optional: true + + '@reflink/reflink-linux-arm64-gnu@0.1.19': + optional: true + + '@reflink/reflink-linux-arm64-musl@0.1.19': + optional: true + + '@reflink/reflink-linux-x64-gnu@0.1.19': + optional: true + + '@reflink/reflink-linux-x64-musl@0.1.19': + optional: true + + '@reflink/reflink-win32-arm64-msvc@0.1.19': + optional: true + + '@reflink/reflink-win32-x64-msvc@0.1.19': + optional: true + + '@reflink/reflink@0.1.19': + optionalDependencies: + '@reflink/reflink-darwin-arm64': 0.1.19 + '@reflink/reflink-darwin-x64': 0.1.19 + '@reflink/reflink-linux-arm64-gnu': 0.1.19 + '@reflink/reflink-linux-arm64-musl': 0.1.19 + '@reflink/reflink-linux-x64-gnu': 0.1.19 + '@reflink/reflink-linux-x64-musl': 0.1.19 + '@reflink/reflink-win32-arm64-msvc': 0.1.19 + '@reflink/reflink-win32-x64-msvc': 0.1.19 + optional: true + '@rolldown/binding-android-arm64@1.0.0-beta.59': optional: true @@ -4133,7 +4952,7 @@ snapshots: '@slack/types': 2.19.0 '@slack/web-api': 7.13.0 '@types/express': 5.0.6 - axios: 1.13.2 + axios: 1.13.2(debug@4.4.3) express: 5.2.1 path-to-regexp: 8.3.0 raw-body: 3.0.2 @@ -4179,7 +4998,7 @@ snapshots: '@slack/types': 2.19.0 '@types/node': 25.0.6 '@types/retry': 0.12.0 - axios: 1.13.2 + axios: 1.13.2(debug@4.4.3) eventemitter3: 5.0.1 form-data: 4.0.5 is-electron: 2.2.2 @@ -4217,6 +5036,8 @@ snapshots: '@thi.ng/errors@2.6.0': optional: true + '@tinyhttp/content-disposition@2.2.2': {} + '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3 @@ -4234,6 +5055,8 @@ snapshots: '@types/aria-query@5.0.4': optional: true + '@types/aws-lambda@8.10.159': {} + '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 @@ -4543,6 +5366,8 @@ snapshots: alien-signals@2.0.8: {} + ansi-escapes@6.2.1: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -4563,6 +5388,13 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + aproba@2.1.0: {} + + are-we-there-yet@3.0.1: + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + argparse@2.0.1: {} aria-query@5.3.0: @@ -4582,6 +5414,10 @@ snapshots: dependencies: tslib: 2.8.1 + async-retry@1.3.3: + dependencies: + retry: 0.13.1 + asynckit@0.4.0: {} atomic-sleep@1.0.0: {} @@ -4604,9 +5440,9 @@ snapshots: audio-type@2.2.1: optional: true - axios@1.13.2: + axios@1.13.2(debug@4.4.3): dependencies: - follow-redirects: 1.15.11 + follow-redirects: 1.15.11(debug@4.4.3) form-data: 4.0.5 proxy-from-env: 1.1.0 transitivePeerDependencies: @@ -4618,6 +5454,8 @@ snapshots: base64-js@1.5.1: {} + before-after-hook@4.0.0: {} + bignumber.js@9.3.1: {} binary-extensions@2.3.0: {} @@ -4695,6 +5533,8 @@ snapshots: chalk@5.6.2: {} + chmodrp@1.0.2: {} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -4711,6 +5551,8 @@ snapshots: dependencies: readdirp: 5.0.0 + chownr@2.0.0: {} + chownr@3.0.0: {} chromium-bidi@12.0.1(devtools-protocol@0.0.1561482): @@ -4719,10 +5561,16 @@ snapshots: mitt: 3.0.1 zod: 3.25.76 + ci-info@4.3.1: {} + class-variance-authority@0.7.1: dependencies: clsx: 2.1.1 + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + cli-highlight@2.1.11: dependencies: chalk: 4.1.2 @@ -4732,14 +5580,39 @@ snapshots: parse5-htmlparser2-tree-adapter: 6.0.1 yargs: 16.2.0 + cli-spinners@2.9.2: {} + cliui@7.0.4: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clsx@2.1.1: {} + cmake-js@7.4.0: + dependencies: + axios: 1.13.2(debug@4.4.3) + debug: 4.4.3 + fs-extra: 11.3.3 + memory-stream: 1.0.0 + node-api-headers: 1.7.0 + npmlog: 6.0.2 + rc: 1.2.8 + semver: 7.7.3 + tar: 6.2.1 + url-join: 4.0.1 + which: 2.0.2 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + codec-parser@2.5.0: optional: true @@ -4751,14 +5624,20 @@ snapshots: color-name@1.1.4: {} + color-support@1.1.3: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 + commander@10.0.1: {} + commander@14.0.2: {} commander@8.3.0: {} + console-control-strings@1.1.0: {} + content-disposition@1.0.1: {} content-type@1.0.5: {} @@ -4791,8 +5670,12 @@ snapshots: dependencies: ms: 2.1.3 + deep-extend@0.6.0: {} + delayed-stream@1.0.0: {} + delegates@1.0.0: {} + depd@2.0.0: {} dequal@2.0.3: @@ -4835,6 +5718,8 @@ snapshots: ee-first@1.1.1: {} + emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -4843,6 +5728,8 @@ snapshots: entities@4.5.0: {} + env-var@7.5.0: {} + es-define-property@1.0.1: {} es-errors@1.3.0: {} @@ -4944,6 +5831,8 @@ snapshots: extend@3.0.2: {} + fast-content-type-parse@3.0.0: {} + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -4978,6 +5867,12 @@ snapshots: transitivePeerDependencies: - supports-color + filename-reserved-regex@3.0.0: {} + + filenamify@6.0.0: + dependencies: + filename-reserved-regex: 3.0.0 + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -4993,7 +5888,9 @@ snapshots: transitivePeerDependencies: - supports-color - follow-redirects@1.15.11: {} + follow-redirects@1.15.11(debug@4.4.3): + optionalDependencies: + debug: 4.4.3 foreground-child@3.3.1: dependencies: @@ -5016,6 +5913,16 @@ snapshots: fresh@2.0.0: {} + fs-extra@11.3.3: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + fsevents@2.3.2: optional: true @@ -5024,6 +5931,17 @@ snapshots: function-bind@1.1.2: {} + gauge@4.0.4: + dependencies: + aproba: 2.1.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + gaxios@7.1.3: dependencies: extend: 3.0.2 @@ -5132,6 +6050,8 @@ snapshots: dependencies: has-symbols: 1.1.0 + has-unicode@2.0.1: {} + hashery@1.4.0: dependencies: hookified: 1.15.0 @@ -5181,12 +6101,40 @@ snapshots: ieee754@1.2.1: {} + ignore@7.0.5: {} + immediate@3.0.6: {} inherits@2.0.4: {} + ini@1.3.8: {} + ipaddr.js@1.9.1: {} + ipull@3.9.3: + dependencies: + '@tinyhttp/content-disposition': 2.2.2 + async-retry: 1.3.3 + chalk: 5.6.2 + ci-info: 4.3.1 + cli-spinners: 2.9.2 + commander: 10.0.1 + eventemitter3: 5.0.1 + filenamify: 6.0.0 + fs-extra: 11.3.3 + is-unicode-supported: 2.1.0 + lifecycle-utils: 2.1.0 + lodash.debounce: 4.0.8 + lowdb: 7.0.1 + pretty-bytes: 6.1.1 + pretty-ms: 8.0.0 + sleep-promise: 9.1.0 + slice-ansi: 7.1.2 + stdout-update: 4.0.1 + strip-ansi: 7.1.2 + optionalDependencies: + '@reflink/reflink': 0.1.19 + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 @@ -5197,22 +6145,34 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.4.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 + is-interactive@2.0.0: {} + is-number@7.0.0: {} is-promise@4.0.0: {} is-stream@2.0.1: {} + is-unicode-supported@1.3.0: {} + + is-unicode-supported@2.1.0: {} + is-url@1.2.4: {} isarray@1.0.0: {} isexe@2.0.0: {} + isexe@3.1.1: {} + istanbul-lib-coverage@3.2.2: {} istanbul-lib-report@3.0.1: @@ -5270,6 +6230,12 @@ snapshots: jsonc-parser@3.3.1: {} + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + jsonwebtoken@9.0.3: dependencies: jws: 4.0.1 @@ -5324,6 +6290,10 @@ snapshots: dependencies: immediate: 3.0.6 + lifecycle-utils@2.1.0: {} + + lifecycle-utils@3.0.1: {} + lightningcss-android-arm64@1.30.2: optional: true @@ -5398,6 +6368,8 @@ snapshots: lodash.clonedeep@4.5.0: {} + lodash.debounce@4.0.8: {} + lodash.includes@4.3.0: {} lodash.isboolean@3.0.3: {} @@ -5414,10 +6386,24 @@ snapshots: lodash@4.17.21: {} + log-symbols@6.0.0: + dependencies: + chalk: 5.6.2 + is-unicode-supported: 1.3.0 + + log-symbols@7.0.1: + dependencies: + is-unicode-supported: 2.1.0 + yoctocolors: 2.1.2 + long@4.0.0: {} long@5.3.2: {} + lowdb@7.0.1: + dependencies: + steno: 4.0.2 + lru-cache@10.4.3: {} lru-cache@11.2.4: {} @@ -5473,6 +6459,10 @@ snapshots: media-typer@1.1.0: {} + memory-stream@1.0.0: + dependencies: + readable-stream: 3.6.2 + merge-descriptors@2.0.0: {} merge2@1.4.1: {} @@ -5494,6 +6484,8 @@ snapshots: dependencies: mime-db: 1.54.0 + mimic-function@5.0.1: {} + minimatch@10.1.1: dependencies: '@isaacs/brace-expansion': 5.0.0 @@ -5502,14 +6494,29 @@ snapshots: dependencies: brace-expansion: 2.0.2 + minimist@1.2.8: {} + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + minipass@7.1.2: {} + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + minizlib@3.1.0: dependencies: minipass: 7.1.2 mitt@3.0.1: {} + mkdirp@1.0.4: {} + mpg123-decoder@1.0.3: dependencies: '@wasm-audio-decoders/common': 9.0.7 @@ -5541,8 +6548,14 @@ snapshots: nanoid@3.3.11: {} + nanoid@5.1.6: {} + negotiator@1.0.0: {} + node-addon-api@8.5.0: {} + + node-api-headers@1.7.0: {} + node-domexception@1.0.0: {} node-fetch@2.7.0: @@ -5555,11 +6568,67 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 + node-llama-cpp@3.14.5(typescript@5.9.3): + dependencies: + '@huggingface/jinja': 0.5.3 + async-retry: 1.3.3 + bytes: 3.1.2 + chalk: 5.6.2 + chmodrp: 1.0.2 + cmake-js: 7.4.0 + cross-spawn: 7.0.6 + env-var: 7.5.0 + filenamify: 6.0.0 + fs-extra: 11.3.3 + ignore: 7.0.5 + ipull: 3.9.3 + is-unicode-supported: 2.1.0 + lifecycle-utils: 3.0.1 + log-symbols: 7.0.1 + nanoid: 5.1.6 + node-addon-api: 8.5.0 + octokit: 5.0.5 + ora: 8.2.0 + pretty-ms: 9.3.0 + proper-lockfile: 4.1.2 + semver: 7.7.3 + simple-git: 3.30.0 + slice-ansi: 7.1.2 + stdout-update: 4.0.1 + strip-ansi: 7.1.2 + validate-npm-package-name: 6.0.2 + which: 5.0.0 + yargs: 17.7.2 + optionalDependencies: + '@node-llama-cpp/linux-arm64': 3.14.5 + '@node-llama-cpp/linux-armv7l': 3.14.5 + '@node-llama-cpp/linux-x64': 3.14.5 + '@node-llama-cpp/linux-x64-cuda': 3.14.5 + '@node-llama-cpp/linux-x64-cuda-ext': 3.14.5 + '@node-llama-cpp/linux-x64-vulkan': 3.14.5 + '@node-llama-cpp/mac-arm64-metal': 3.14.5 + '@node-llama-cpp/mac-x64': 3.14.5 + '@node-llama-cpp/win-arm64': 3.14.5 + '@node-llama-cpp/win-x64': 3.14.5 + '@node-llama-cpp/win-x64-cuda': 3.14.5 + '@node-llama-cpp/win-x64-cuda-ext': 3.14.5 + '@node-llama-cpp/win-x64-vulkan': 3.14.5 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + node-wav@0.0.2: optional: true normalize-path@3.0.0: {} + npmlog@6.0.2: + dependencies: + are-we-there-yet: 3.0.1 + console-control-strings: 1.1.0 + gauge: 4.0.4 + set-blocking: 2.0.0 + object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -5568,6 +6637,20 @@ snapshots: obug@2.1.1: {} + octokit@5.0.5: + dependencies: + '@octokit/app': 16.1.2 + '@octokit/core': 7.0.6 + '@octokit/oauth-app': 8.0.3 + '@octokit/plugin-paginate-graphql': 6.0.0(@octokit/core@7.0.6) + '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) + '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) + '@octokit/plugin-retry': 8.0.3(@octokit/core@7.0.6) + '@octokit/plugin-throttling': 11.0.3(@octokit/core@7.0.6) + '@octokit/request-error': 7.1.0 + '@octokit/types': 16.0.0 + '@octokit/webhooks': 14.2.0 + ogg-opus-decoder@1.7.3: dependencies: '@wasm-audio-decoders/common': 9.0.7 @@ -5590,6 +6673,10 @@ snapshots: dependencies: wrappy: 1.0.2 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + openai@6.10.0(ws@8.19.0)(zod@4.3.5): optionalDependencies: ws: 8.19.0 @@ -5600,6 +6687,18 @@ snapshots: '@wasm-audio-decoders/common': 9.0.7 optional: true + ora@8.2.0: + dependencies: + chalk: 5.6.2 + cli-cursor: 5.0.0 + cli-spinners: 2.9.2 + is-interactive: 2.0.0 + is-unicode-supported: 2.1.0 + log-symbols: 6.0.0 + stdin-discarder: 0.2.2 + string-width: 7.2.0 + strip-ansi: 7.1.2 + osc-progress@0.2.0: {} oxlint-tsgolint@0.11.0: @@ -5652,6 +6751,10 @@ snapshots: pako@1.0.11: {} + parse-ms@3.0.0: {} + + parse-ms@4.0.0: {} + parse5-htmlparser2-tree-adapter@6.0.1: dependencies: parse5: 6.0.1 @@ -5728,6 +6831,8 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + pretty-bytes@6.1.1: {} + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 @@ -5735,6 +6840,14 @@ snapshots: react-is: 17.0.2 optional: true + pretty-ms@8.0.0: + dependencies: + parse-ms: 3.0.0 + + pretty-ms@9.3.0: + dependencies: + parse-ms: 4.0.0 + prism-media@1.3.5: optional: true @@ -5837,6 +6950,13 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 + 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@17.0.2: optional: true @@ -5850,6 +6970,12 @@ snapshots: string_decoder: 1.1.1 util-deprecate: 1.0.2 + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + readable-stream@4.5.2: dependencies: abort-controller: 3.0.0 @@ -5872,6 +6998,11 @@ snapshots: resolve-pkg-maps@1.0.0: {} + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + retry@0.12.0: {} retry@0.13.1: {} @@ -5981,6 +7112,8 @@ snapshots: transitivePeerDependencies: - supports-color + set-blocking@2.0.0: {} + setimmediate@1.0.5: {} setprototypeof@1.2.0: {} @@ -6062,6 +7195,14 @@ snapshots: dependencies: signal-polyfill: 0.2.2 + simple-git@3.30.0: + dependencies: + '@kwsites/file-exists': 1.1.1 + '@kwsites/promise-deferred': 1.1.1 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + simple-yenc@1.0.4: optional: true @@ -6073,6 +7214,13 @@ snapshots: sisteransi@1.0.5: {} + sleep-promise@9.1.0: {} + + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + sonic-boom@4.2.0: dependencies: atomic-sleep: 1.0.0 @@ -6094,6 +7242,17 @@ snapshots: std-env@3.10.0: {} + stdin-discarder@0.2.2: {} + + stdout-update@4.0.1: + dependencies: + ansi-escapes: 6.2.1 + ansi-styles: 6.2.3 + string-width: 7.2.0 + strip-ansi: 7.1.2 + + steno@4.0.2: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -6106,6 +7265,12 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.2 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.4.0 + strip-ansi: 7.1.2 + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -6122,6 +7287,8 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-json-comments@2.0.1: {} + strtok3@10.3.4: dependencies: '@tokenizer/token': 0.3.0 @@ -6140,6 +7307,15 @@ snapshots: tailwindcss@4.1.17: {} + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + tar@7.5.2: dependencies: '@isaacs/fs-minipass': 4.0.1 @@ -6177,6 +7353,8 @@ snapshots: dependencies: is-number: 7.0.0 + toad-cache@3.7.0: {} + toidentifier@1.0.1: {} token-types@6.1.2: @@ -6234,16 +7412,26 @@ snapshots: pako: 0.2.9 tiny-inflate: 1.0.3 + universal-github-app-jwt@2.2.2: {} + + universal-user-agent@7.0.3: {} + + universalify@2.0.1: {} + unpipe@1.0.0: {} urijs@1.19.11: {} + url-join@4.0.1: {} + util-deprecate@1.0.2: {} uuid@11.1.0: {} uuid@8.3.2: {} + validate-npm-package-name@6.0.2: {} + vary@1.1.2: {} vite@7.3.1(@types/node@25.0.6)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)(yaml@2.8.2): @@ -6316,11 +7504,19 @@ snapshots: dependencies: isexe: 2.0.0 + which@5.0.0: + dependencies: + isexe: 3.1.1 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 + wide-align@1.1.5: + dependencies: + string-width: 4.2.3 + wireit@0.14.12: dependencies: brace-expansion: 4.0.1 @@ -6360,6 +7556,8 @@ snapshots: yargs-parser@20.2.9: {} + yargs-parser@21.1.1: {} + yargs@16.2.0: dependencies: cliui: 7.0.4 @@ -6370,6 +7568,18 @@ snapshots: y18n: 5.0.8 yargs-parser: 20.2.9 + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yoctocolors@2.1.2: {} + zod-to-json-schema@3.25.1(zod@3.25.76): dependencies: zod: 3.25.76 diff --git a/src/agents/agent-scope.ts b/src/agents/agent-scope.ts index 9ad92d830..4e9d9f2b2 100644 --- a/src/agents/agent-scope.ts +++ b/src/agents/agent-scope.ts @@ -22,6 +22,7 @@ type ResolvedAgentConfig = { workspace?: string; agentDir?: string; model?: string; + memorySearch?: AgentEntry["memorySearch"]; humanDelay?: AgentEntry["humanDelay"]; identity?: AgentEntry["identity"]; groupChat?: AgentEntry["groupChat"]; @@ -95,6 +96,7 @@ export function resolveAgentConfig( typeof entry.workspace === "string" ? entry.workspace : undefined, agentDir: typeof entry.agentDir === "string" ? entry.agentDir : undefined, model: typeof entry.model === "string" ? entry.model : undefined, + memorySearch: entry.memorySearch, humanDelay: entry.humanDelay, identity: entry.identity, groupChat: entry.groupChat, diff --git a/src/agents/clawdbot-tools.ts b/src/agents/clawdbot-tools.ts index 851f0a123..c9852268b 100644 --- a/src/agents/clawdbot-tools.ts +++ b/src/agents/clawdbot-tools.ts @@ -9,6 +9,10 @@ import type { AnyAgentTool } from "./tools/common.js"; import { createCronTool } from "./tools/cron-tool.js"; import { createGatewayTool } from "./tools/gateway-tool.js"; import { createImageTool } from "./tools/image-tool.js"; +import { + createMemoryGetTool, + createMemorySearchTool, +} from "./tools/memory-tool.js"; import { createMessageTool } from "./tools/message-tool.js"; import { createNodesTool } from "./tools/nodes-tool.js"; import { createSessionStatusTool } from "./tools/session-status-tool.js"; @@ -43,6 +47,14 @@ export function createClawdbotTools(options?: { config: options?.config, agentDir: options?.agentDir, }); + const memorySearchTool = createMemorySearchTool({ + config: options?.config, + agentSessionKey: options?.agentSessionKey, + }); + const memoryGetTool = createMemoryGetTool({ + config: options?.config, + agentSessionKey: options?.agentSessionKey, + }); const tools: AnyAgentTool[] = [ createBrowserTool({ defaultControlUrl: options?.browserControlUrl, @@ -89,6 +101,9 @@ export function createClawdbotTools(options?: { agentSessionKey: options?.agentSessionKey, config: options?.config, }), + ...(memorySearchTool && memoryGetTool + ? [memorySearchTool, memoryGetTool] + : []), ...(imageTool ? [imageTool] : []), ]; diff --git a/src/agents/memory-search.test.ts b/src/agents/memory-search.test.ts new file mode 100644 index 000000000..03595d49b --- /dev/null +++ b/src/agents/memory-search.test.ts @@ -0,0 +1,56 @@ +import { describe, expect, it } from "vitest"; + +import { resolveMemorySearchConfig } from "./memory-search.js"; + +describe("memory search config", () => { + it("returns null when disabled", () => { + const cfg = { + agents: { + defaults: { + memorySearch: { enabled: true }, + }, + list: [ + { + id: "main", + default: true, + memorySearch: { enabled: false }, + }, + ], + }, + }; + const resolved = resolveMemorySearchConfig(cfg, "main"); + expect(resolved).toBeNull(); + }); + + it("merges defaults and overrides", () => { + const cfg = { + agents: { + defaults: { + memorySearch: { + provider: "openai", + model: "text-embedding-3-small", + chunking: { tokens: 500, overlap: 100 }, + query: { maxResults: 4, minScore: 0.2 }, + }, + }, + list: [ + { + id: "main", + default: true, + memorySearch: { + chunking: { tokens: 320 }, + query: { maxResults: 8 }, + }, + }, + ], + }, + }; + const resolved = resolveMemorySearchConfig(cfg, "main"); + expect(resolved?.provider).toBe("openai"); + expect(resolved?.model).toBe("text-embedding-3-small"); + expect(resolved?.chunking.tokens).toBe(320); + expect(resolved?.chunking.overlap).toBe(100); + expect(resolved?.query.maxResults).toBe(8); + expect(resolved?.query.minScore).toBe(0.2); + }); +}); diff --git a/src/agents/memory-search.ts b/src/agents/memory-search.ts new file mode 100644 index 000000000..02ba369a0 --- /dev/null +++ b/src/agents/memory-search.ts @@ -0,0 +1,134 @@ +import os from "node:os"; +import path from "node:path"; + +import type { ClawdbotConfig, MemorySearchConfig } from "../config/config.js"; +import { resolveStateDir } from "../config/paths.js"; +import { resolveUserPath } from "../utils.js"; +import { resolveAgentConfig } from "./agent-scope.js"; + +export type ResolvedMemorySearchConfig = { + enabled: boolean; + provider: "openai" | "local"; + fallback: "openai" | "none"; + model: string; + local: { + modelPath?: string; + modelCacheDir?: string; + }; + store: { + driver: "sqlite"; + path: string; + }; + chunking: { + tokens: number; + overlap: number; + }; + sync: { + onSessionStart: boolean; + onSearch: boolean; + watch: boolean; + watchDebounceMs: number; + intervalMinutes: number; + }; + query: { + maxResults: number; + minScore: number; + }; +}; + +const DEFAULT_MODEL = "text-embedding-3-small"; +const DEFAULT_CHUNK_TOKENS = 400; +const DEFAULT_CHUNK_OVERLAP = 80; +const DEFAULT_WATCH_DEBOUNCE_MS = 1500; +const DEFAULT_MAX_RESULTS = 6; +const DEFAULT_MIN_SCORE = 0.35; + +function resolveStorePath(agentId: string, raw?: string): string { + const stateDir = resolveStateDir(process.env, os.homedir); + const fallback = path.join(stateDir, "memory", `${agentId}.sqlite`); + if (!raw) return fallback; + const withToken = raw.includes("{agentId}") + ? raw.replaceAll("{agentId}", agentId) + : raw; + return resolveUserPath(withToken); +} + +function mergeConfig( + defaults: MemorySearchConfig | undefined, + overrides: MemorySearchConfig | undefined, + agentId: string, +): ResolvedMemorySearchConfig { + const enabled = overrides?.enabled ?? defaults?.enabled ?? true; + const provider = overrides?.provider ?? defaults?.provider ?? "openai"; + const fallback = overrides?.fallback ?? defaults?.fallback ?? "openai"; + const model = overrides?.model ?? defaults?.model ?? DEFAULT_MODEL; + const local = { + modelPath: overrides?.local?.modelPath ?? defaults?.local?.modelPath, + modelCacheDir: + overrides?.local?.modelCacheDir ?? defaults?.local?.modelCacheDir, + }; + const store = { + driver: overrides?.store?.driver ?? defaults?.store?.driver ?? "sqlite", + path: resolveStorePath( + agentId, + overrides?.store?.path ?? defaults?.store?.path, + ), + }; + const chunking = { + tokens: + overrides?.chunking?.tokens ?? + defaults?.chunking?.tokens ?? + DEFAULT_CHUNK_TOKENS, + overlap: + overrides?.chunking?.overlap ?? + defaults?.chunking?.overlap ?? + DEFAULT_CHUNK_OVERLAP, + }; + const sync = { + onSessionStart: + overrides?.sync?.onSessionStart ?? defaults?.sync?.onSessionStart ?? true, + onSearch: overrides?.sync?.onSearch ?? defaults?.sync?.onSearch ?? true, + watch: overrides?.sync?.watch ?? defaults?.sync?.watch ?? true, + watchDebounceMs: + overrides?.sync?.watchDebounceMs ?? + defaults?.sync?.watchDebounceMs ?? + DEFAULT_WATCH_DEBOUNCE_MS, + intervalMinutes: + overrides?.sync?.intervalMinutes ?? defaults?.sync?.intervalMinutes ?? 0, + }; + const query = { + maxResults: + overrides?.query?.maxResults ?? + defaults?.query?.maxResults ?? + DEFAULT_MAX_RESULTS, + minScore: + overrides?.query?.minScore ?? + defaults?.query?.minScore ?? + DEFAULT_MIN_SCORE, + }; + + const overlap = Math.max(0, Math.min(chunking.overlap, chunking.tokens - 1)); + const minScore = Math.max(0, Math.min(1, query.minScore)); + return { + enabled, + provider, + fallback, + model, + local, + store, + chunking: { tokens: Math.max(1, chunking.tokens), overlap }, + sync, + query: { ...query, minScore }, + }; +} + +export function resolveMemorySearchConfig( + cfg: ClawdbotConfig, + agentId: string, +): ResolvedMemorySearchConfig | null { + const defaults = cfg.agents?.defaults?.memorySearch; + const overrides = resolveAgentConfig(cfg, agentId)?.memorySearch; + const resolved = mergeConfig(defaults, overrides, agentId); + if (!resolved.enabled) return null; + return resolved; +} diff --git a/src/agents/tool-display.json b/src/agents/tool-display.json index d008eadca..b3609d5c7 100644 --- a/src/agents/tool-display.json +++ b/src/agents/tool-display.json @@ -222,6 +222,16 @@ "title": "Session Status", "detailKeys": ["sessionKey", "model"] }, + "memory_search": { + "emoji": "🧠", + "title": "Memory Search", + "detailKeys": ["query"] + }, + "memory_get": { + "emoji": "📓", + "title": "Memory Get", + "detailKeys": ["path", "from", "lines"] + }, "whatsapp_login": { "emoji": "🟢", "title": "WhatsApp Login", diff --git a/src/agents/tools/memory-tool.ts b/src/agents/tools/memory-tool.ts new file mode 100644 index 000000000..de2b0251b --- /dev/null +++ b/src/agents/tools/memory-tool.ts @@ -0,0 +1,101 @@ +import { Type } from "@sinclair/typebox"; + +import type { ClawdbotConfig } from "../../config/config.js"; +import { getMemorySearchManager } from "../../memory/index.js"; +import { resolveSessionAgentId } from "../agent-scope.js"; +import { resolveMemorySearchConfig } from "../memory-search.js"; +import type { AnyAgentTool } from "./common.js"; +import { jsonResult, readNumberParam, readStringParam } from "./common.js"; + +const MemorySearchSchema = Type.Object({ + query: Type.String(), + maxResults: Type.Optional(Type.Number()), + minScore: Type.Optional(Type.Number()), +}); + +const MemoryGetSchema = Type.Object({ + path: Type.String(), + from: Type.Optional(Type.Number()), + lines: Type.Optional(Type.Number()), +}); + +export function createMemorySearchTool(options: { + config?: ClawdbotConfig; + agentSessionKey?: string; +}): AnyAgentTool | null { + const cfg = options.config; + if (!cfg) return null; + const agentId = resolveSessionAgentId({ + sessionKey: options.agentSessionKey, + config: cfg, + }); + if (!resolveMemorySearchConfig(cfg, agentId)) return null; + return { + label: "Memory Search", + name: "memory_search", + description: + "Search agent memory files (MEMORY.md + memory/*.md) using semantic vectors.", + parameters: MemorySearchSchema, + execute: async (_toolCallId, params) => { + const query = readStringParam(params, "query", { required: true }); + const maxResults = readNumberParam(params, "maxResults"); + const minScore = readNumberParam(params, "minScore"); + const { manager, error } = await getMemorySearchManager({ + cfg, + agentId, + }); + if (!manager) { + return jsonResult({ results: [], disabled: true, error }); + } + const results = await manager.search(query, { + maxResults, + minScore, + sessionKey: options.agentSessionKey, + }); + const status = manager.status(); + return jsonResult({ + results, + provider: status.provider, + model: status.model, + fallback: status.fallback, + }); + }, + }; +} + +export function createMemoryGetTool(options: { + config?: ClawdbotConfig; + agentSessionKey?: string; +}): AnyAgentTool | null { + const cfg = options.config; + if (!cfg) return null; + const agentId = resolveSessionAgentId({ + sessionKey: options.agentSessionKey, + config: cfg, + }); + if (!resolveMemorySearchConfig(cfg, agentId)) return null; + return { + label: "Memory Get", + name: "memory_get", + description: "Read a memory file by path (workspace-relative).", + parameters: MemoryGetSchema, + execute: async (_toolCallId, params) => { + const relPath = readStringParam(params, "path", { required: true }); + const from = readNumberParam(params, "from", { integer: true }); + const lines = readNumberParam(params, "lines", { integer: true }); + const { manager, error } = await getMemorySearchManager({ + cfg, + agentId, + }); + if (!manager) { + return jsonResult({ path: relPath, text: "", disabled: true, error }); + } + const result = await manager.readFile({ + relPath, + from: from ?? undefined, + lines: lines ?? undefined, + }); + return jsonResult(result); + }, + }; +} diff --git a/src/auto-reply/reply.ts b/src/auto-reply/reply.ts index ef12a91b4..a8fc461fa 100644 --- a/src/auto-reply/reply.ts +++ b/src/auto-reply/reply.ts @@ -40,7 +40,6 @@ import { import { normalizeMainKey } from "../routing/session-key.js"; import { defaultRuntime } from "../runtime.js"; import { INTERNAL_MESSAGE_PROVIDER } from "../utils/message-provider.js"; -import { isReasoningTagProvider } from "../utils/provider-utils.js"; import { resolveCommandAuthorization } from "./command-auth.js"; import { hasControlCommand } from "./command-detection.js"; import { @@ -493,6 +492,15 @@ export async function getReplyFromConfig( modelAliases: configuredAliases, allowStatusDirective, }); + const hasInlineStatus = + parsedDirectives.hasStatusDirective && + parsedDirectives.cleaned.trim().length > 0; + if (hasInlineStatus) { + parsedDirectives = { + ...parsedDirectives, + hasStatusDirective: false, + }; + } if ( isGroup && ctx.WasMentioned !== true && @@ -522,7 +530,6 @@ export async function getReplyFromConfig( if (noMentions.trim().length > 0) { const directiveOnlyCheck = parseInlineDirectives(noMentions, { modelAliases: configuredAliases, - allowStatusDirective, }); if (directiveOnlyCheck.cleaned.trim().length > 0) { const allowInlineStatus = @@ -698,11 +705,10 @@ export async function getReplyFromConfig( ? undefined : directives.rawModelDirective; + const inlineStatusRequested = + hasInlineStatus && allowTextCommands && command.isAuthorizedSender; + if (!command.isAuthorizedSender) { - // Treat slash tokens as plain text for unauthorized senders. - cleanedBody = existingBody; - sessionCtx.Body = cleanedBody; - sessionCtx.BodyStripped = cleanedBody; directives = { ...directives, hasThinkDirective: false, @@ -863,11 +869,7 @@ export async function getReplyFromConfig( cfg, agentId, isGroup, - }) && - directives.hasStatusDirective && - allowTextCommands && - command.isAuthorizedSender && - command.commandBodyNormalized !== "/status"; + }) && inlineStatusRequested; if (handleInlineStatus) { const inlineStatusReply = await buildStatusReply({ cfg, @@ -1158,7 +1160,6 @@ export async function getReplyFromConfig( resolvedQueue.mode === "collect" || resolvedQueue.mode === "steer-backlog"; const authProfileId = sessionEntry?.authProfileOverride; - const followupRun = { prompt: queuedBody, messageId: sessionCtx.MessageSid, @@ -1197,7 +1198,7 @@ export async function getReplyFromConfig( ownerNumbers: command.ownerList.length > 0 ? command.ownerList : undefined, extraSystemPrompt: extraSystemPrompt || undefined, - ...(isReasoningTagProvider(provider) ? { enforceFinalTag: true } : {}), + ...(provider === "ollama" ? { enforceFinalTag: true } : {}), }, }; diff --git a/src/cli/memory-cli.ts b/src/cli/memory-cli.ts new file mode 100644 index 000000000..3fd694d23 --- /dev/null +++ b/src/cli/memory-cli.ts @@ -0,0 +1,124 @@ +import chalk from "chalk"; +import type { Command } from "commander"; + +import { resolveDefaultAgentId } from "../agents/agent-scope.js"; +import { loadConfig } from "../config/config.js"; +import { getMemorySearchManager } from "../memory/index.js"; +import { defaultRuntime } from "../runtime.js"; + +type MemoryCommandOptions = { + agent?: string; + json?: boolean; +}; + +function resolveAgent(cfg: ReturnType, agent?: string) { + const trimmed = agent?.trim(); + if (trimmed) return trimmed; + return resolveDefaultAgentId(cfg); +} + +export function registerMemoryCli(program: Command) { + const memory = program.command("memory").description("Memory search tools"); + + memory + .command("status") + .description("Show memory search index status") + .option("--agent ", "Agent id (default: default agent)") + .option("--json", "Print JSON") + .action(async (opts: MemoryCommandOptions) => { + const cfg = loadConfig(); + const agentId = resolveAgent(cfg, opts.agent); + const { manager, error } = await getMemorySearchManager({ cfg, agentId }); + if (!manager) { + defaultRuntime.log(error ?? "Memory search disabled."); + return; + } + const status = manager.status(); + if (opts.json) { + defaultRuntime.log(JSON.stringify(status, null, 2)); + return; + } + const lines = [ + `${chalk.bold.cyan("Memory Search")} (${agentId})`, + `Provider: ${status.provider} (requested: ${status.requestedProvider})`, + status.fallback + ? chalk.yellow(`Fallback: ${status.fallback.from}`) + : null, + `Files: ${status.files}`, + `Chunks: ${status.chunks}`, + `Dirty: ${status.dirty ? "yes" : "no"}`, + `Index: ${status.dbPath}`, + ].filter(Boolean) as string[]; + if (status.fallback?.reason) { + lines.push(chalk.gray(status.fallback.reason)); + } + defaultRuntime.log(lines.join("\n")); + }); + + memory + .command("index") + .description("Reindex memory files") + .option("--agent ", "Agent id (default: default agent)") + .option("--force", "Force full reindex", false) + .action(async (opts: MemoryCommandOptions & { force?: boolean }) => { + const cfg = loadConfig(); + const agentId = resolveAgent(cfg, opts.agent); + const { manager, error } = await getMemorySearchManager({ cfg, agentId }); + if (!manager) { + defaultRuntime.log(error ?? "Memory search disabled."); + return; + } + await manager.sync({ reason: "cli", force: opts.force }); + defaultRuntime.log("Memory index updated."); + }); + + memory + .command("search") + .description("Search memory files") + .argument("", "Search query") + .option("--agent ", "Agent id (default: default agent)") + .option("--max-results ", "Max results", (v) => Number(v)) + .option("--min-score ", "Minimum score", (v) => Number(v)) + .option("--json", "Print JSON") + .action( + async ( + query: string, + opts: MemoryCommandOptions & { + maxResults?: number; + minScore?: number; + }, + ) => { + const cfg = loadConfig(); + const agentId = resolveAgent(cfg, opts.agent); + const { manager, error } = await getMemorySearchManager({ + cfg, + agentId, + }); + if (!manager) { + defaultRuntime.log(error ?? "Memory search disabled."); + return; + } + const results = await manager.search(query, { + maxResults: opts.maxResults, + minScore: opts.minScore, + }); + if (opts.json) { + defaultRuntime.log(JSON.stringify({ results }, null, 2)); + return; + } + if (results.length === 0) { + defaultRuntime.log("No matches."); + return; + } + const lines: string[] = []; + for (const result of results) { + lines.push( + `${chalk.green(result.score.toFixed(3))} ${result.path}:${result.startLine}-${result.endLine}`, + ); + lines.push(chalk.gray(result.snippet)); + lines.push(""); + } + defaultRuntime.log(lines.join("\n").trim()); + }, + ); +} diff --git a/src/cli/program.ts b/src/cli/program.ts index dd65c81e8..9fc9d8258 100644 --- a/src/cli/program.ts +++ b/src/cli/program.ts @@ -50,6 +50,7 @@ import { registerDocsCli } from "./docs-cli.js"; import { registerGatewayCli } from "./gateway-cli.js"; import { registerHooksCli } from "./hooks-cli.js"; import { registerLogsCli } from "./logs-cli.js"; +import { registerMemoryCli } from "./memory-cli.js"; import { registerModelsCli } from "./models-cli.js"; import { registerNodesCli } from "./nodes-cli.js"; import { registerPairingCli } from "./pairing-cli.js"; @@ -1213,6 +1214,7 @@ ${theme.muted("Docs:")} ${formatDocsLink( registerDaemonCli(program); registerGatewayCli(program); registerLogsCli(program); + registerMemoryCli(program); registerModelsCli(program); registerNodesCli(program); registerSandboxCli(program); diff --git a/src/config/schema.ts b/src/config/schema.ts index ebc388643..3b7ac9006 100644 --- a/src/config/schema.ts +++ b/src/config/schema.ts @@ -115,6 +115,23 @@ const FIELD_LABELS: Record = { "gateway.reload.mode": "Config Reload Mode", "gateway.reload.debounceMs": "Config Reload Debounce (ms)", "agents.defaults.workspace": "Workspace", + "agents.defaults.memorySearch": "Memory Search", + "agents.defaults.memorySearch.enabled": "Enable Memory Search", + "agents.defaults.memorySearch.provider": "Memory Search Provider", + "agents.defaults.memorySearch.model": "Memory Search Model", + "agents.defaults.memorySearch.fallback": "Memory Search Fallback", + "agents.defaults.memorySearch.local.modelPath": "Local Embedding Model Path", + "agents.defaults.memorySearch.store.path": "Memory Search Index Path", + "agents.defaults.memorySearch.chunking.tokens": "Memory Chunk Tokens", + "agents.defaults.memorySearch.chunking.overlap": + "Memory Chunk Overlap Tokens", + "agents.defaults.memorySearch.sync.onSessionStart": "Index on Session Start", + "agents.defaults.memorySearch.sync.onSearch": "Index on Search (Lazy)", + "agents.defaults.memorySearch.sync.watch": "Watch Memory Files", + "agents.defaults.memorySearch.sync.watchDebounceMs": + "Memory Watch Debounce (ms)", + "agents.defaults.memorySearch.query.maxResults": "Memory Search Max Results", + "agents.defaults.memorySearch.query.minScore": "Memory Search Min Score", "auth.profiles": "Auth Profiles", "auth.order": "Auth Profile Order", "auth.cooldowns.billingBackoffHours": "Billing Backoff (hours)", @@ -215,6 +232,20 @@ const FIELD_HELP: Record = { "Failure window (hours) for backoff counters (default: 24).", "agents.defaults.models": "Configured model catalog (keys are full provider/model IDs).", + "agents.defaults.memorySearch": + "Vector search over MEMORY.md and memory/*.md (per-agent overrides supported).", + "agents.defaults.memorySearch.provider": + 'Embedding provider ("openai" or "local").', + "agents.defaults.memorySearch.local.modelPath": + "Local GGUF model path or hf: URI (node-llama-cpp).", + "agents.defaults.memorySearch.fallback": + 'Fallback to OpenAI when local embeddings fail ("openai" or "none").', + "agents.defaults.memorySearch.store.path": + "SQLite index path (default: ~/.clawdbot/memory/{agentId}.sqlite).", + "agents.defaults.memorySearch.sync.onSearch": + "Lazy sync: reindex on first search after a change.", + "agents.defaults.memorySearch.sync.watch": + "Watch memory files for changes (chokidar).", "plugins.enabled": "Enable plugin/extension loading (default: true).", "plugins.allow": "Optional allowlist of plugin ids; when set, only listed plugins load.", diff --git a/src/config/types.ts b/src/config/types.ts index 200e14b45..f9d91ab28 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -996,6 +996,47 @@ export type AgentToolsConfig = { }; }; +export type MemorySearchConfig = { + /** Enable vector memory search (default: true). */ + enabled?: boolean; + /** Embedding provider mode. */ + provider?: "openai" | "local"; + /** Fallback behavior when local embeddings fail. */ + fallback?: "openai" | "none"; + /** Embedding model id (remote) or alias (local). */ + model?: string; + /** Local embedding settings (node-llama-cpp). */ + local?: { + /** GGUF model path or hf: URI. */ + modelPath?: string; + /** Optional cache directory for local models. */ + modelCacheDir?: string; + }; + /** Index storage configuration. */ + store?: { + driver?: "sqlite"; + path?: string; + }; + /** Chunking configuration. */ + chunking?: { + tokens?: number; + overlap?: number; + }; + /** Sync behavior. */ + sync?: { + onSessionStart?: boolean; + onSearch?: boolean; + watch?: boolean; + watchDebounceMs?: number; + intervalMinutes?: number; + }; + /** Query behavior. */ + query?: { + maxResults?: number; + minScore?: number; + }; +}; + export type ToolsConfig = { allow?: string[]; deny?: string[]; @@ -1070,6 +1111,7 @@ export type AgentConfig = { workspace?: string; agentDir?: string; model?: string; + memorySearch?: MemorySearchConfig; /** Human-like delay between block replies for this agent. */ humanDelay?: HumanDelayConfig; identity?: IdentityConfig; @@ -1534,6 +1576,8 @@ export type AgentDefaultsConfig = { contextPruning?: AgentContextPruningConfig; /** Compaction tuning and pre-compaction memory flush behavior. */ compaction?: AgentCompactionConfig; + /** Vector memory search configuration (per-agent overrides supported). */ + memorySearch?: MemorySearchConfig; /** Default thinking level when no /think directive is present. */ thinkingDefault?: "off" | "minimal" | "low" | "medium" | "high"; /** Default verbose level when no /verbose directive is present. */ diff --git a/src/config/zod-schema.ts b/src/config/zod-schema.ts index dd8405684..caadbf74b 100644 --- a/src/config/zod-schema.ts +++ b/src/config/zod-schema.ts @@ -867,6 +867,48 @@ const AgentToolsSchema = z }) .optional(); +const MemorySearchSchema = z + .object({ + enabled: z.boolean().optional(), + provider: z.union([z.literal("openai"), z.literal("local")]).optional(), + fallback: z.union([z.literal("openai"), z.literal("none")]).optional(), + model: z.string().optional(), + local: z + .object({ + modelPath: z.string().optional(), + modelCacheDir: z.string().optional(), + }) + .optional(), + store: z + .object({ + driver: z.literal("sqlite").optional(), + path: z.string().optional(), + }) + .optional(), + chunking: z + .object({ + tokens: z.number().int().positive().optional(), + overlap: z.number().int().nonnegative().optional(), + }) + .optional(), + sync: z + .object({ + onSessionStart: z.boolean().optional(), + onSearch: z.boolean().optional(), + watch: z.boolean().optional(), + watchDebounceMs: z.number().int().nonnegative().optional(), + intervalMinutes: z.number().int().nonnegative().optional(), + }) + .optional(), + query: z + .object({ + maxResults: z.number().int().positive().optional(), + minScore: z.number().min(0).max(1).optional(), + }) + .optional(), + }) + .optional(); + const AgentEntrySchema = z.object({ id: z.string(), default: z.boolean().optional(), @@ -874,6 +916,7 @@ const AgentEntrySchema = z.object({ workspace: z.string().optional(), agentDir: z.string().optional(), model: z.string().optional(), + memorySearch: MemorySearchSchema, humanDelay: HumanDelaySchema.optional(), identity: IdentitySchema, groupChat: GroupChatSchema, @@ -1098,6 +1141,7 @@ const AgentDefaultsSchema = z userTimezone: z.string().optional(), contextTokens: z.number().int().positive().optional(), cliBackends: z.record(z.string(), CliBackendSchema).optional(), + memorySearch: MemorySearchSchema, contextPruning: z .object({ mode: z diff --git a/src/gateway/gateway-models.profiles.live.test.ts b/src/gateway/gateway-models.profiles.live.test.ts index c40dde12e..56390cfc9 100644 --- a/src/gateway/gateway-models.profiles.live.test.ts +++ b/src/gateway/gateway-models.profiles.live.test.ts @@ -238,32 +238,21 @@ function buildLiveGatewayConfig(params: { candidates: Array>; providerOverrides?: Record; }): ClawdbotConfig { + const providerOverrides = params.providerOverrides ?? {}; const lmstudioProvider = params.cfg.models?.providers?.lmstudio; const baseProviders = params.cfg.models?.providers ?? {}; - const nextProviders = params.providerOverrides - ? { - ...baseProviders, - ...(lmstudioProvider - ? { - lmstudio: { - ...lmstudioProvider, - api: "openai-completions", - }, - } - : {}), - ...params.providerOverrides, - } - : { - ...baseProviders, - ...(lmstudioProvider - ? { - lmstudio: { - ...lmstudioProvider, - api: "openai-completions", - }, - } - : {}), - }; + const nextProviders = { + ...baseProviders, + ...(lmstudioProvider + ? { + lmstudio: { + ...lmstudioProvider, + api: "openai-completions", + }, + } + : {}), + ...providerOverrides, + }; const providers = Object.keys(nextProviders).length > 0 ? nextProviders : baseProviders; return { diff --git a/src/memory/embeddings.ts b/src/memory/embeddings.ts new file mode 100644 index 000000000..3a5b1cb02 --- /dev/null +++ b/src/memory/embeddings.ts @@ -0,0 +1,194 @@ +import type { Llama, LlamaEmbeddingContext, LlamaModel } from "node-llama-cpp"; +import { resolveApiKeyForProvider } from "../agents/model-auth.js"; +import type { ClawdbotConfig } from "../config/config.js"; + +export type EmbeddingProvider = { + id: string; + model: string; + embedQuery: (text: string) => Promise; + embedBatch: (texts: string[]) => Promise; +}; + +export type EmbeddingProviderResult = { + provider: EmbeddingProvider; + requestedProvider: "openai" | "local"; + fallbackFrom?: "local"; + fallbackReason?: string; +}; + +export type EmbeddingProviderOptions = { + config: ClawdbotConfig; + agentDir?: string; + provider: "openai" | "local"; + model: string; + fallback: "openai" | "none"; + local?: { + modelPath?: string; + modelCacheDir?: string; + }; +}; + +const DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1"; +const DEFAULT_LOCAL_MODEL = + "hf:ggml-org/embeddinggemma-300M-GGUF/embeddinggemma-300M-Q8_0.gguf"; + +function normalizeOpenAiModel(model: string): string { + const trimmed = model.trim(); + if (!trimmed) return "text-embedding-3-small"; + if (trimmed.startsWith("openai/")) return trimmed.slice("openai/".length); + return trimmed; +} + +async function createOpenAiEmbeddingProvider( + options: EmbeddingProviderOptions, +): Promise { + const { apiKey } = await resolveApiKeyForProvider({ + provider: "openai", + cfg: options.config, + agentDir: options.agentDir, + }); + + const providerConfig = options.config.models?.providers?.openai; + const baseUrl = providerConfig?.baseUrl?.trim() || DEFAULT_OPENAI_BASE_URL; + const url = `${baseUrl.replace(/\/$/, "")}/embeddings`; + const headerOverrides = providerConfig?.headers ?? {}; + const headers: Record = { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}`, + ...headerOverrides, + }; + const model = normalizeOpenAiModel(options.model); + + const embed = async (input: string[]): Promise => { + if (input.length === 0) return []; + const res = await fetch(url, { + method: "POST", + headers, + body: JSON.stringify({ model, input }), + }); + if (!res.ok) { + const text = await res.text(); + throw new Error(`openai embeddings failed: ${res.status} ${text}`); + } + const payload = (await res.json()) as { + data?: Array<{ embedding?: number[] }>; + }; + const data = payload.data ?? []; + return data.map((entry) => entry.embedding ?? []); + }; + + return { + id: "openai", + model, + embedQuery: async (text) => { + const [vec] = await embed([text]); + return vec ?? []; + }, + embedBatch: embed, + }; +} + +async function createLocalEmbeddingProvider( + options: EmbeddingProviderOptions, +): Promise { + const modelPath = options.local?.modelPath?.trim() || DEFAULT_LOCAL_MODEL; + const modelCacheDir = options.local?.modelCacheDir?.trim(); + + // Lazy-load node-llama-cpp to keep startup light unless local is enabled. + const { getLlama, resolveModelFile, LlamaLogLevel } = await import( + "node-llama-cpp" + ); + + let llama: Llama | null = null; + let embeddingModel: LlamaModel | null = null; + let embeddingContext: LlamaEmbeddingContext | null = null; + + const ensureContext = async () => { + if (!llama) { + llama = await getLlama({ logLevel: LlamaLogLevel.error }); + } + if (!embeddingModel) { + const resolved = await resolveModelFile( + modelPath, + modelCacheDir || undefined, + ); + embeddingModel = await llama.loadModel({ modelPath: resolved }); + } + if (!embeddingContext) { + embeddingContext = await embeddingModel.createEmbeddingContext(); + } + return embeddingContext; + }; + + return { + id: "local", + model: modelPath, + embedQuery: async (text) => { + const ctx = await ensureContext(); + const embedding = await ctx.getEmbeddingFor(text); + return Array.from(embedding.vector) as number[]; + }, + embedBatch: async (texts) => { + const ctx = await ensureContext(); + const embeddings = await Promise.all( + texts.map(async (text) => { + const embedding = await ctx.getEmbeddingFor(text); + return Array.from(embedding.vector) as number[]; + }), + ); + return embeddings; + }, + }; +} + +export async function createEmbeddingProvider( + options: EmbeddingProviderOptions, +): Promise { + const requestedProvider = options.provider; + if (options.provider === "local") { + try { + const provider = await createLocalEmbeddingProvider(options); + return { provider, requestedProvider }; + } catch (err) { + const reason = formatLocalSetupError(err); + if (options.fallback === "openai") { + try { + const provider = await createOpenAiEmbeddingProvider(options); + return { + provider, + requestedProvider, + fallbackFrom: "local", + fallbackReason: reason, + }; + } catch (fallbackErr) { + throw new Error( + `${reason}\n\nFallback to OpenAI failed: ${formatError(fallbackErr)}`, + ); + } + } + throw new Error(reason); + } + } + const provider = await createOpenAiEmbeddingProvider(options); + return { provider, requestedProvider }; +} + +function formatError(err: unknown): string { + if (err instanceof Error) return err.message; + return String(err); +} + +function formatLocalSetupError(err: unknown): string { + const detail = formatError(err); + return [ + "Local embeddings unavailable.", + detail ? `Reason: ${detail}` : undefined, + "To enable local embeddings:", + "1) pnpm approve-builds", + "2) select node-llama-cpp", + "3) pnpm rebuild node-llama-cpp", + 'Or set agents.defaults.memorySearch.provider = "openai" (remote).', + ] + .filter(Boolean) + .join("\n"); +} diff --git a/src/memory/index.test.ts b/src/memory/index.test.ts new file mode 100644 index 000000000..f088eb074 --- /dev/null +++ b/src/memory/index.test.ts @@ -0,0 +1,98 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; + +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +import { getMemorySearchManager } from "./index.js"; + +vi.mock("./embeddings.js", () => { + const embedText = (text: string) => { + const lower = text.toLowerCase(); + const alpha = lower.split("alpha").length - 1; + const beta = lower.split("beta").length - 1; + return [alpha, beta, 1]; + }; + return { + createEmbeddingProvider: async () => ({ + requestedProvider: "openai", + provider: { + id: "mock", + model: "mock-embed", + embedQuery: async (text: string) => embedText(text), + embedBatch: async (texts: string[]) => texts.map(embedText), + }, + }), + }; +}); + +describe("memory index", () => { + let workspaceDir: string; + let indexPath: string; + + beforeEach(async () => { + workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-mem-")); + indexPath = path.join(workspaceDir, "index.sqlite"); + await fs.mkdir(path.join(workspaceDir, "memory")); + await fs.writeFile( + path.join(workspaceDir, "memory", "2026-01-12.md"), + "# Log\nAlpha memory line.\nAnother line.", + ); + await fs.writeFile( + path.join(workspaceDir, "MEMORY.md"), + "Beta knowledge base entry.", + ); + }); + + afterEach(async () => { + await fs.rm(workspaceDir, { recursive: true, force: true }); + }); + + it("indexes memory files and searches by vector", async () => { + const cfg = { + agents: { + defaults: { + workspace: workspaceDir, + memorySearch: { + provider: "openai", + model: "mock-embed", + store: { path: indexPath }, + sync: { watch: false, onSessionStart: false, onSearch: true }, + query: { minScore: 0 }, + }, + }, + list: [{ id: "main", default: true }], + }, + }; + const result = await getMemorySearchManager({ cfg, agentId: "main" }); + expect(result.manager).not.toBeNull(); + if (!result.manager) throw new Error("manager missing"); + await result.manager.sync({ force: true }); + const results = await result.manager.search("alpha"); + expect(results.length).toBeGreaterThan(0); + expect(results[0]?.path).toContain("memory/2026-01-12.md"); + }); + + it("rejects reading non-memory paths", async () => { + const cfg = { + agents: { + defaults: { + workspace: workspaceDir, + memorySearch: { + provider: "openai", + model: "mock-embed", + store: { path: indexPath }, + sync: { watch: false, onSessionStart: false, onSearch: true }, + }, + }, + list: [{ id: "main", default: true }], + }, + }; + const result = await getMemorySearchManager({ cfg, agentId: "main" }); + expect(result.manager).not.toBeNull(); + if (!result.manager) throw new Error("manager missing"); + await expect( + result.manager.readFile({ relPath: "NOTES.md" }), + ).rejects.toThrow("path required"); + }); +}); diff --git a/src/memory/index.ts b/src/memory/index.ts new file mode 100644 index 000000000..1b3d4fc43 --- /dev/null +++ b/src/memory/index.ts @@ -0,0 +1,641 @@ +import crypto from "node:crypto"; +import fsSync from "node:fs"; +import fs from "node:fs/promises"; +import path from "node:path"; + +import { DatabaseSync } from "node:sqlite"; +import chokidar, { type FSWatcher } from "chokidar"; + +import { + resolveAgentDir, + resolveAgentWorkspaceDir, +} from "../agents/agent-scope.js"; +import type { ResolvedMemorySearchConfig } from "../agents/memory-search.js"; +import { resolveMemorySearchConfig } from "../agents/memory-search.js"; +import type { ClawdbotConfig } from "../config/config.js"; +import { resolveUserPath, truncateUtf16Safe } from "../utils.js"; +import { + createEmbeddingProvider, + type EmbeddingProvider, + type EmbeddingProviderResult, +} from "./embeddings.js"; + +export type MemorySearchResult = { + path: string; + startLine: number; + endLine: number; + score: number; + snippet: string; +}; + +type MemoryFileEntry = { + path: string; + absPath: string; + mtimeMs: number; + size: number; + hash: string; +}; + +type MemoryChunk = { + startLine: number; + endLine: number; + text: string; + hash: string; +}; + +type MemoryIndexMeta = { + model: string; + provider: string; + chunkTokens: number; + chunkOverlap: number; +}; + +const META_KEY = "memory_index_meta_v1"; +const SNIPPET_MAX_CHARS = 700; + +const INDEX_CACHE = new Map(); + +export class MemoryIndexManager { + private readonly cfg: ClawdbotConfig; + private readonly agentId: string; + private readonly workspaceDir: string; + private readonly settings: ResolvedMemorySearchConfig; + private readonly provider: EmbeddingProvider; + private readonly requestedProvider: "openai" | "local"; + private readonly fallbackReason?: string; + private readonly db: DatabaseSync; + private watcher: FSWatcher | null = null; + private watchTimer: NodeJS.Timeout | null = null; + private intervalTimer: NodeJS.Timeout | null = null; + private dirty = false; + private sessionWarm = new Set(); + private syncing: Promise | null = null; + + static async get(params: { + cfg: ClawdbotConfig; + agentId: string; + }): Promise { + const { cfg, agentId } = params; + const settings = resolveMemorySearchConfig(cfg, agentId); + if (!settings) return null; + const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId); + const key = `${agentId}:${workspaceDir}:${JSON.stringify(settings)}`; + const existing = INDEX_CACHE.get(key); + if (existing) return existing; + const providerResult = await createEmbeddingProvider({ + config: cfg, + agentDir: resolveAgentDir(cfg, agentId), + provider: settings.provider, + model: settings.model, + fallback: settings.fallback, + local: settings.local, + }); + const manager = new MemoryIndexManager({ + cfg, + agentId, + workspaceDir, + settings, + providerResult, + }); + INDEX_CACHE.set(key, manager); + return manager; + } + + private constructor(params: { + cfg: ClawdbotConfig; + agentId: string; + workspaceDir: string; + settings: ResolvedMemorySearchConfig; + providerResult: EmbeddingProviderResult; + }) { + this.cfg = params.cfg; + this.agentId = params.agentId; + this.workspaceDir = params.workspaceDir; + this.settings = params.settings; + this.provider = params.providerResult.provider; + this.requestedProvider = params.providerResult.requestedProvider; + this.fallbackReason = params.providerResult.fallbackReason; + this.db = this.openDatabase(); + this.ensureSchema(); + this.ensureWatcher(); + this.ensureIntervalSync(); + this.dirty = true; + } + + async warmSession(sessionKey?: string): Promise { + if (!this.settings.sync.onSessionStart) return; + const key = sessionKey?.trim() || ""; + if (key && this.sessionWarm.has(key)) return; + await this.sync({ reason: "session-start" }); + if (key) this.sessionWarm.add(key); + } + + async search( + query: string, + opts?: { + maxResults?: number; + minScore?: number; + sessionKey?: string; + }, + ): Promise { + await this.warmSession(opts?.sessionKey); + if (this.settings.sync.onSearch && this.dirty) { + await this.sync({ reason: "search" }); + } + const cleaned = query.trim(); + if (!cleaned) return []; + const queryVec = await this.provider.embedQuery(cleaned); + if (queryVec.length === 0) return []; + const candidates = this.listChunks(); + const scored = candidates + .map((chunk) => ({ + chunk, + score: cosineSimilarity(queryVec, chunk.embedding), + })) + .filter((entry) => Number.isFinite(entry.score)); + const minScore = opts?.minScore ?? this.settings.query.minScore; + const maxResults = opts?.maxResults ?? this.settings.query.maxResults; + return scored + .filter((entry) => entry.score >= minScore) + .sort((a, b) => b.score - a.score) + .slice(0, maxResults) + .map((entry) => ({ + path: entry.chunk.path, + startLine: entry.chunk.startLine, + endLine: entry.chunk.endLine, + score: entry.score, + snippet: truncateUtf16Safe(entry.chunk.text, SNIPPET_MAX_CHARS), + })); + } + + async sync(params?: { reason?: string; force?: boolean }): Promise { + if (this.syncing) return this.syncing; + this.syncing = this.runSync(params).finally(() => { + this.syncing = null; + }); + return this.syncing; + } + + async readFile(params: { + relPath: string; + from?: number; + lines?: number; + }): Promise<{ text: string; path: string }> { + const relPath = normalizeRelPath(params.relPath); + if (!relPath || !isMemoryPath(relPath)) { + throw new Error("path required"); + } + const absPath = path.resolve(this.workspaceDir, relPath); + if (!absPath.startsWith(this.workspaceDir)) { + throw new Error("path escapes workspace"); + } + const content = await fs.readFile(absPath, "utf-8"); + if (!params.from && !params.lines) { + return { text: content, path: relPath }; + } + const lines = content.split("\n"); + const start = Math.max(1, params.from ?? 1); + const count = Math.max(1, params.lines ?? lines.length); + const slice = lines.slice(start - 1, start - 1 + count); + return { text: slice.join("\n"), path: relPath }; + } + + status(): { + files: number; + chunks: number; + dirty: boolean; + workspaceDir: string; + dbPath: string; + provider: string; + model: string; + requestedProvider: string; + fallback?: { from: string; reason?: string }; + } { + const files = this.db.prepare(`SELECT COUNT(*) as c FROM files`).get() as { + c: number; + }; + const chunks = this.db + .prepare(`SELECT COUNT(*) as c FROM chunks`) + .get() as { + c: number; + }; + return { + files: files?.c ?? 0, + chunks: chunks?.c ?? 0, + dirty: this.dirty, + workspaceDir: this.workspaceDir, + dbPath: this.settings.store.path, + provider: this.provider.id, + model: this.provider.model, + requestedProvider: this.requestedProvider, + fallback: this.fallbackReason + ? { from: "local", reason: this.fallbackReason } + : undefined, + }; + } + + private openDatabase(): DatabaseSync { + const dbPath = resolveUserPath(this.settings.store.path); + const dir = path.dirname(dbPath); + ensureDir(dir); + return new DatabaseSync(dbPath); + } + + private ensureSchema() { + this.db.exec(` + CREATE TABLE IF NOT EXISTS meta ( + key TEXT PRIMARY KEY, + value TEXT NOT NULL + ); + `); + this.db.exec(` + CREATE TABLE IF NOT EXISTS files ( + path TEXT PRIMARY KEY, + hash TEXT NOT NULL, + mtime INTEGER NOT NULL, + size INTEGER NOT NULL + ); + `); + this.db.exec(` + CREATE TABLE IF NOT EXISTS chunks ( + id TEXT PRIMARY KEY, + path TEXT NOT NULL, + start_line INTEGER NOT NULL, + end_line INTEGER NOT NULL, + hash TEXT NOT NULL, + model TEXT NOT NULL, + text TEXT NOT NULL, + embedding TEXT NOT NULL, + updated_at INTEGER NOT NULL + ); + `); + this.db.exec(`CREATE INDEX IF NOT EXISTS idx_chunks_path ON chunks(path);`); + } + + private ensureWatcher() { + if (!this.settings.sync.watch || this.watcher) return; + const watchPaths = [ + path.join(this.workspaceDir, "MEMORY.md"), + path.join(this.workspaceDir, "memory"), + ]; + this.watcher = chokidar.watch(watchPaths, { + ignoreInitial: true, + awaitWriteFinish: { + stabilityThreshold: this.settings.sync.watchDebounceMs, + pollInterval: 100, + }, + }); + const markDirty = () => { + this.dirty = true; + this.scheduleWatchSync(); + }; + this.watcher.on("add", markDirty); + this.watcher.on("change", markDirty); + this.watcher.on("unlink", markDirty); + } + + private ensureIntervalSync() { + const minutes = this.settings.sync.intervalMinutes; + if (!minutes || minutes <= 0 || this.intervalTimer) return; + const ms = minutes * 60 * 1000; + this.intervalTimer = setInterval(() => { + void this.sync({ reason: "interval" }); + }, ms); + } + + private scheduleWatchSync() { + if (!this.settings.sync.watch) return; + if (this.watchTimer) clearTimeout(this.watchTimer); + this.watchTimer = setTimeout(() => { + this.watchTimer = null; + void this.sync({ reason: "watch" }); + }, this.settings.sync.watchDebounceMs); + } + + private listChunks(): Array<{ + path: string; + startLine: number; + endLine: number; + text: string; + embedding: number[]; + }> { + const rows = this.db + .prepare( + `SELECT path, start_line, end_line, text, embedding FROM chunks WHERE model = ?`, + ) + .all(this.provider.model) as Array<{ + path: string; + start_line: number; + end_line: number; + text: string; + embedding: string; + }>; + return rows.map((row) => ({ + path: row.path, + startLine: row.start_line, + endLine: row.end_line, + text: row.text, + embedding: parseEmbedding(row.embedding), + })); + } + + private async runSync(params?: { reason?: string; force?: boolean }) { + const meta = this.readMeta(); + const needsFullReindex = + params?.force || + !meta || + meta.model !== this.provider.model || + meta.provider !== this.provider.id || + meta.chunkTokens !== this.settings.chunking.tokens || + meta.chunkOverlap !== this.settings.chunking.overlap; + if (needsFullReindex) { + this.resetIndex(); + } + + const files = await listMemoryFiles(this.workspaceDir); + const fileEntries = await Promise.all( + files.map(async (file) => buildFileEntry(file, this.workspaceDir)), + ); + const activePaths = new Set(fileEntries.map((entry) => entry.path)); + + for (const entry of fileEntries) { + const record = this.db + .prepare(`SELECT hash FROM files WHERE path = ?`) + .get(entry.path) as { hash: string } | undefined; + if (!needsFullReindex && record?.hash === entry.hash) { + continue; + } + await this.indexFile(entry); + } + + const staleRows = this.db.prepare(`SELECT path FROM files`).all() as Array<{ + path: string; + }>; + for (const stale of staleRows) { + if (activePaths.has(stale.path)) continue; + this.db.prepare(`DELETE FROM files WHERE path = ?`).run(stale.path); + this.db.prepare(`DELETE FROM chunks WHERE path = ?`).run(stale.path); + } + + this.writeMeta({ + model: this.provider.model, + provider: this.provider.id, + chunkTokens: this.settings.chunking.tokens, + chunkOverlap: this.settings.chunking.overlap, + }); + this.dirty = false; + } + + private resetIndex() { + this.db.exec(`DELETE FROM files`); + this.db.exec(`DELETE FROM chunks`); + } + + private readMeta(): MemoryIndexMeta | null { + const row = this.db + .prepare(`SELECT value FROM meta WHERE key = ?`) + .get(META_KEY) as { value: string } | undefined; + if (!row?.value) return null; + try { + return JSON.parse(row.value) as MemoryIndexMeta; + } catch { + return null; + } + } + + private writeMeta(meta: MemoryIndexMeta) { + const value = JSON.stringify(meta); + this.db + .prepare( + `INSERT INTO meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value=excluded.value`, + ) + .run(META_KEY, value); + } + + private async indexFile(entry: MemoryFileEntry) { + const content = await fs.readFile(entry.absPath, "utf-8"); + const chunks = chunkMarkdown(content, this.settings.chunking); + const embeddings = await this.provider.embedBatch( + chunks.map((chunk) => chunk.text), + ); + const now = Date.now(); + this.db.prepare(`DELETE FROM chunks WHERE path = ?`).run(entry.path); + for (let i = 0; i < chunks.length; i++) { + const chunk = chunks[i]; + const embedding = embeddings[i] ?? []; + const id = hashText( + `${entry.path}:${chunk.startLine}:${chunk.endLine}:${chunk.hash}:${this.provider.model}`, + ); + this.db + .prepare( + `INSERT INTO chunks (id, path, start_line, end_line, hash, model, text, embedding, updated_at) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(id) DO UPDATE SET + hash=excluded.hash, + model=excluded.model, + text=excluded.text, + embedding=excluded.embedding, + updated_at=excluded.updated_at`, + ) + .run( + id, + entry.path, + chunk.startLine, + chunk.endLine, + chunk.hash, + this.provider.model, + chunk.text, + JSON.stringify(embedding), + now, + ); + } + this.db + .prepare( + `INSERT INTO files (path, hash, mtime, size) VALUES (?, ?, ?, ?) + ON CONFLICT(path) DO UPDATE SET hash=excluded.hash, mtime=excluded.mtime, size=excluded.size`, + ) + .run(entry.path, entry.hash, entry.mtimeMs, entry.size); + } +} + +export type MemorySearchManagerResult = { + manager: MemoryIndexManager | null; + error?: string; +}; + +export async function getMemorySearchManager(params: { + cfg: ClawdbotConfig; + agentId: string; +}): Promise { + try { + const manager = await MemoryIndexManager.get(params); + return { manager }; + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + return { manager: null, error: message }; + } +} + +function ensureDir(dir: string): string { + try { + fsSync.mkdirSync(dir, { recursive: true }); + } catch {} + return dir; +} + +function normalizeRelPath(value: string): string { + const trimmed = value.trim().replace(/^[./]+/, ""); + return trimmed.replace(/\\/g, "/"); +} + +function isMemoryPath(relPath: string): boolean { + const normalized = normalizeRelPath(relPath); + if (!normalized) return false; + if (normalized === "MEMORY.md" || normalized === "memory.md") return true; + return normalized.startsWith("memory/"); +} + +async function listMemoryFiles(workspaceDir: string): Promise { + const result: string[] = []; + const memoryFile = path.join(workspaceDir, "MEMORY.md"); + const altMemoryFile = path.join(workspaceDir, "memory.md"); + if (await exists(memoryFile)) result.push(memoryFile); + if (await exists(altMemoryFile)) result.push(altMemoryFile); + const memoryDir = path.join(workspaceDir, "memory"); + if (await exists(memoryDir)) { + await walkDir(memoryDir, result); + } + return result; +} + +async function walkDir(dir: string, files: string[]) { + const entries = await fs.readdir(dir, { withFileTypes: true }); + for (const entry of entries) { + const full = path.join(dir, entry.name); + if (entry.isDirectory()) { + await walkDir(full, files); + continue; + } + if (!entry.isFile()) continue; + if (!entry.name.endsWith(".md")) continue; + files.push(full); + } +} + +async function exists(filePath: string): Promise { + try { + await fs.access(filePath); + return true; + } catch { + return false; + } +} + +async function buildFileEntry( + absPath: string, + workspaceDir: string, +): Promise { + const stat = await fs.stat(absPath); + const content = await fs.readFile(absPath, "utf-8"); + const hash = hashText(content); + return { + path: path.relative(workspaceDir, absPath).replace(/\\/g, "/"), + absPath, + mtimeMs: stat.mtimeMs, + size: stat.size, + hash, + }; +} + +function hashText(value: string): string { + return crypto.createHash("sha256").update(value).digest("hex"); +} + +function chunkMarkdown( + content: string, + chunking: { tokens: number; overlap: number }, +): MemoryChunk[] { + const lines = content.split("\n"); + if (lines.length === 0) return []; + const maxChars = Math.max(32, chunking.tokens * 4); + const overlapChars = Math.max(0, chunking.overlap * 4); + const chunks: MemoryChunk[] = []; + + let current: Array<{ line: string; lineNo: number }> = []; + let currentChars = 0; + + const flush = () => { + if (current.length === 0) return; + const firstEntry = current[0]; + const lastEntry = current[current.length - 1]; + if (!firstEntry || !lastEntry) return; + const text = current.map((entry) => entry.line).join("\n"); + const startLine = firstEntry.lineNo; + const endLine = lastEntry.lineNo; + chunks.push({ + startLine, + endLine, + text, + hash: hashText(text), + }); + }; + + const carryOverlap = () => { + if (overlapChars <= 0 || current.length === 0) { + current = []; + currentChars = 0; + return; + } + let acc = 0; + const kept: Array<{ line: string; lineNo: number }> = []; + for (let i = current.length - 1; i >= 0; i -= 1) { + const entry = current[i]; + if (!entry) continue; + acc += entry.line.length + 1; + kept.unshift(entry); + if (acc >= overlapChars) break; + } + current = kept; + currentChars = kept.reduce((sum, entry) => sum + entry.line.length + 1, 0); + }; + + for (let i = 0; i < lines.length; i += 1) { + const line = lines[i] ?? ""; + const lineNo = i + 1; + const lineSize = line.length + 1; + if (currentChars + lineSize > maxChars && current.length > 0) { + flush(); + carryOverlap(); + } + current.push({ line, lineNo }); + currentChars += lineSize; + } + flush(); + return chunks; +} + +function parseEmbedding(raw: string): number[] { + try { + const parsed = JSON.parse(raw) as number[]; + return Array.isArray(parsed) ? parsed : []; + } catch { + return []; + } +} + +function cosineSimilarity(a: number[], b: number[]): number { + if (a.length === 0 || b.length === 0) return 0; + const len = Math.min(a.length, b.length); + let dot = 0; + let normA = 0; + let normB = 0; + for (let i = 0; i < len; i += 1) { + const av = a[i] ?? 0; + const bv = b[i] ?? 0; + dot += av * bv; + normA += av * av; + normB += bv * bv; + } + if (normA === 0 || normB === 0) return 0; + return dot / (Math.sqrt(normA) * Math.sqrt(normB)); +}