From fa5645baedce31914e44651c5b0ba871424a266e Mon Sep 17 00:00:00 2001 From: Ishaan Gupta Date: Wed, 23 Sep 2026 19:16:57 +0530 Subject: [PATCH 1/4] Add OpenCode 2 plugin with full feature parity OpenCode 2 rejects the V1 root export, so 2.0.13 fails to load for every OpenCode 2 user (#74). Ship a server plugin at `opencode-supermemory/server` (resolved automatically by OpenCode 2), a `./tui` companion that renders activity notices as toasts, and a shared `./rpc` contract, while keeping the root export unchanged for OpenCode V1. The V2 runtime mirrors main's V1 behavior: direct/advisory/off recall with per-session dedupe and 3s fail-open timeouts, first-message profile context, keyword nudges, the shared `supermemory` tool plus a read-only `supermemory_recall` tool that the installer auto-allows, bounded and idempotent automatic capture from the session transcript, native compaction enrichment with summary capture (`compactionEnabled`), update checks, and activity notices over plugin RPC. Recall context is re-applied on every model call for the same prompt because OpenCode 2 hook messages are request-local. Shared services now back both generations: the tool executor, compaction prompt, activity notice formatting, and a comment-preserving JSONC editor that registers `plugin`, `plugins`, and the recall permission. The installer and `status` report both registrations. Also fix the `src/cli.ts` typecheck failure that blocked the 2.0.14 release, import jsonc-parser's ESM build so bundles load under Node and Bun, run tests in the release workflow, and bump to 2.0.15. --- .github/workflows/release.yml | 4 + README.md | 114 ++- bun.lock | 578 ++++++++++++ package.json | 44 +- server.ts | 4 + src/cli.ts | 96 +- src/config.ts | 7 + src/index.ts | 376 +------- src/rpc.ts | 59 ++ src/server.ts | 15 + src/services/activity.ts | 136 ++- src/services/compaction-prompt.ts | 71 ++ src/services/compaction.ts | 43 +- src/services/memory-tool.test.ts | 147 +++ src/services/memory-tool.ts | 382 ++++++++ src/services/opencode-config.test.ts | 76 ++ src/services/opencode-config.ts | 189 ++++ src/services/opencode-permissions.ts | 10 + src/tui.ts | 34 + src/v2/index.ts | 4 + src/v2/runtime.test.ts | 466 +++++++++ src/v2/runtime.ts | 1308 ++++++++++++++++++++++++++ src/version.ts | 2 +- tui.ts | 2 + 24 files changed, 3654 insertions(+), 513 deletions(-) create mode 100644 server.ts create mode 100644 src/rpc.ts create mode 100644 src/server.ts create mode 100644 src/services/compaction-prompt.ts create mode 100644 src/services/memory-tool.test.ts create mode 100644 src/services/memory-tool.ts create mode 100644 src/services/opencode-config.test.ts create mode 100644 src/services/opencode-config.ts create mode 100644 src/services/opencode-permissions.ts create mode 100644 src/tui.ts create mode 100644 src/v2/index.ts create mode 100644 src/v2/runtime.test.ts create mode 100644 src/v2/runtime.ts create mode 100644 tui.ts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 541c312..921af5d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,6 +50,10 @@ jobs: if: steps.version-check.outputs.changed == 'true' run: bun run typecheck + - name: Test + if: steps.version-check.outputs.changed == 'true' + run: bun test + - name: Build if: steps.version-check.outputs.changed == 'true' run: bun run build diff --git a/README.md b/README.md index 6354dc5..d0d24a5 100644 --- a/README.md +++ b/README.md @@ -13,9 +13,13 @@ OpenCode plugin for persistent memory using [Supermemory](https://supermemory.ai). Your agent remembers what you tell it, across sessions and across projects. +One package supports both OpenCode generations: OpenCode V1 loads the root entry from +the `plugin` array, and OpenCode 2 loads `opencode-supermemory/server` (plus a small TUI +companion for notices) from the `plugins` array. See [OpenCode 2](#opencode-2). +
-[Installation](#installation) · [Features](#features) · [Tool usage](#tool-usage) · [Memory scoping](#memory-scoping) · [Configuration](#configuration) · [License](#license) +[Installation](#installation) · [OpenCode 2](#opencode-2) · [Features](#features) · [Tool usage](#tool-usage) · [Memory scoping](#memory-scoping) · [Configuration](#configuration) · [License](#license)
@@ -51,12 +55,14 @@ If you're an LLM agent helping set up opencode-supermemory, follow these steps: bunx opencode-supermemory@latest install --no-tui ``` -This registers the plugin in `~/.config/opencode/opencode.jsonc` and creates the -`/supermemory-init` command. Add `--disable-context-recovery` if the user also has +This registers the plugin in `~/.config/opencode/opencode.jsonc` for both OpenCode V1 +and OpenCode 2, and creates the `/supermemory-index` command. Add +`--disable-context-recovery` if the user also has [Oh My OpenCode](#usage-with-oh-my-opencode) installed, to avoid its auto-compact hook -fighting with this plugin's compaction. +fighting with this plugin's V1 compaction. -- Register the plugin in `~/.config/opencode/opencode.jsonc` +- Register the plugin in `~/.config/opencode/opencode.jsonc` (`plugin` for V1, `plugins` + for OpenCode 2, plus an `allow` rule for the read-only `supermemory_recall` tool) - Create the `/supermemory-index` command (`/supermemory-init` is an alias) #### Step 2: Verify the config @@ -65,14 +71,24 @@ fighting with this plugin's compaction. cat ~/.config/opencode/opencode.jsonc ``` -Should contain `"plugin": ["opencode-supermemory"]`. If not, add it manually: +Should contain the entries below. The installer preserves comments and other settings and +is safe to re-run; if anything is missing, add it manually: ```jsonc { + // OpenCode V1 "plugin": [ - "opencode-supermemory", + "opencode-supermemory@latest", // ... other plugins ], + // OpenCode 2 + "plugins": [ + "opencode-supermemory", + // ... other OpenCode 2 plugins + ], + "permissions": [ + { "action": "supermemory_recall", "resource": "*", "effect": "allow" }, + ], } ``` @@ -93,9 +109,11 @@ For headless environments, set `SUPERMEMORY_API_KEY` manually, or create **Step 4: Verify setup** -Tell the user to restart OpenCode and run `bunx opencode-supermemory@latest status`. If -it's not connected, check: the user is authenticated (or `SUPERMEMORY_API_KEY` is set), -the plugin is in `opencode.jsonc`, and `~/.opencode-supermemory.log` for errors. +Tell the user to restart OpenCode and run `bunx opencode-supermemory@latest status`. The +status output lists whether the V1 and OpenCode 2 entries are registered. If it's not +connected, check: the user is authenticated (or `SUPERMEMORY_API_KEY` is set), the plugin +is in `opencode.jsonc`, `opencode plugin list` shows `supermemory` on OpenCode 2, and +`~/.opencode-supermemory.log` for errors. **Step 5: Initialize codebase memory (optional)** @@ -109,7 +127,7 @@ Run `/supermemory-index` to have the agent explore and memorize the codebase. `/ | --- | --- | | 🧠 **Context injection**
On a session's first message, the agent silently receives your profile, all project knowledge, and (if `autoRecallEveryPrompt` is on) a semantic search over personal memories. | 🔎 **Reasoned recall**
Every turn, the agent is shown a directive asking it to decide whether recalling memory would help before answering. It searches via the `supermemory` tool only when it decides to; the search itself is auto-approved. | | 💾 **Automatic capture**
Completed turns are saved every `captureEveryNTurns` turns, with any remainder flushed when the session ends or OpenCode shuts down. Synthetic plugin context is excluded and `` content is redacted. | 🗣️ **Keyword detection**
Saying "remember", "save this", "don't forget", or a custom pattern nudges the agent to save to memory. | -| 🧭 **Codebase indexing**
`/supermemory-init` has the agent explore and memorize the codebase's structure, patterns, and conventions. | 🗜️ **Preemptive compaction**
At 80% context capacity, triggers OpenCode's summarization, injects project memories into the summary, and saves the summary itself as a memory. | +| 🧭 **Codebase indexing**
`/supermemory-init` has the agent explore and memorize the codebase's structure, patterns, and conventions. | 🗜️ **Compaction memory**
On OpenCode V1, triggers summarization at 80% context capacity. On OpenCode 2, enriches the native compaction request. Both inject project memories into the summary and save the summary itself as a memory. | | 🔒 **Privacy**
Content wrapped in `...` is never stored. | 🔔 **Update notices**
Checks npm for a newer release on session start and surfaces a one-line notice. | ``` @@ -166,12 +184,68 @@ Add custom triggers via `keywordPatterns` config. Run `/supermemory-index` to explore and memorize your codebase structure, patterns, and conventions. `/supermemory-init` is an alias. -### Preemptive Compaction +### Compaction Memory + +On OpenCode V1, when context hits 80% capacity (`compactionThreshold`) the plugin triggers +OpenCode's summarization, injects project memories into the summary prompt, and saves the +resulting summary as a memory. -When context hits 80% capacity: +On OpenCode 2, OpenCode owns the compaction trigger and model. The plugin hooks the native +compaction request to add the same project memories, then saves each successful summary as +a memory. Set `compactionEnabled: false` to opt out on OpenCode 2. + +### Activity Notices + +Supermemory shows a short native notice when it recalls memories, saves a turn, falls open +because recall was unavailable, or a newer release exists. Notices never enter model +context. On OpenCode V1 they are TUI toasts; on OpenCode 2 they are rendered by the +`opencode-supermemory/tui` companion, which OpenCode loads automatically next to the +server plugin. Set `SUPERMEMORY_DEBUG=1` to show a `[recall-decision]` line in each reply while testing -recall. +advisory recall. + +## OpenCode 2 + +OpenCode 2 uses the plural `plugins` config key and the new `@opencode/plugin` API. The +installer writes both generations, so one `opencode.jsonc` works for `opencode` (V1) and +OpenCode 2 side by side: + +```jsonc +{ + "plugin": ["opencode-supermemory@latest"], + "plugins": ["opencode-supermemory"], + "permissions": [ + { "action": "supermemory_recall", "resource": "*", "effect": "allow" }, + ], +} +``` + +OpenCode 2 resolves the package's `./server` export for the server plugin (id +`supermemory`) and `./tui` for the notice companion (id `supermemory.tui`). Verify with +`opencode plugin list` (or `v2 plugin registered` in `~/.opencode-supermemory.log`), and +update with `opencode plugin update opencode-supermemory`. + +What is the same on both generations: + +- Direct recall on substantive prompts, advisory mode, and `recallMode: "off"` +- First-message profile injection, keyword nudges, and automatic capture with the same + cadence, privacy redaction, and idempotent capture IDs +- The `supermemory` tool with identical modes, scopes, and result formatting +- Activity notices and update checks + +What differs on OpenCode 2: + +- Recall runs through the read-only `supermemory_recall` tool (search only). The installer + allows it without prompting; `add`, `forget`, and the rest stay behind the normal + `supermemory` permission. An explicit `deny` for `supermemory_recall` is preserved. +- Compaction is native: the plugin enriches OpenCode's compaction request and saves the + summary instead of triggering compaction itself (`compactionEnabled`). +- Recalled context is attached to the outgoing model request for the current prompt rather + than persisted into the transcript. + +To roll back on OpenCode 2 only, remove `"opencode-supermemory"` from `plugins` (or prefix +it with `-`) and restart. The V1 `plugin` entry is unaffected. ## Tool usage @@ -267,9 +341,12 @@ does not require a migration. // Extra keyword patterns for memory detection (regex) "keywordPatterns": ["log\\s+this", "write\\s+down"], - // Context usage ratio that triggers compaction (0-1) + // OpenCode V1: context usage ratio that triggers compaction (0-1) "compactionThreshold": 0.8, + // OpenCode 2: enrich native compaction with project memories and save summaries + "compactionEnabled": true, + // Save completed conversation batches every N turns (0 = session end only) "captureEveryNTurns": 3, @@ -332,14 +409,19 @@ bun run build bun run typecheck ``` -Local install: +Local install (OpenCode V1 loads the built package; OpenCode 2 loads `server.ts` and +`tui.ts` from the checkout, so `bun install` is enough): ```jsonc { "plugin": ["file:///path/to/opencode-supermemory"], + "plugins": ["/path/to/opencode-supermemory"], } ``` +`opencode plugin list` only shows package plugins, so confirm a checkout loaded by looking +for `v2 plugin init` and `v2 plugin registered` in `~/.opencode-supermemory.log`. + Logs: ```bash diff --git a/bun.lock b/bun.lock index 32a3f60..143ec47 100644 --- a/bun.lock +++ b/bun.lock @@ -6,29 +6,607 @@ "name": "opencode-plugin", "devDependencies": { "@opencode-ai/plugin": "^1.0.162", + "@opencode/plugin": "2.0.15", "@types/bun": "latest", + "jsonc-parser": "3.3.1", "supermemory": "^4.0.0", "typescript": "^5.7.3", }, }, }, "packages": { + "@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="], + + "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], + + "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="], + + "@aws-crypto/sha256-js": ["@aws-crypto/sha256-js@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA=="], + + "@aws-crypto/supports-web-crypto": ["@aws-crypto/supports-web-crypto@5.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg=="], + + "@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="], + + "@aws-sdk/client-cognito-identity": ["@aws-sdk/client-cognito-identity@3.1057.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.15", "@aws-sdk/credential-provider-node": "^3.972.47", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.5", "@smithy/fetch-http-handler": "^5.4.5", "@smithy/node-http-handler": "^4.7.5", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-5MliYkp2u0+2arTp5fZIaxl+xmm90LEKv/VeSxhfNQW4t0fvWJrNO429/jchWQenNoDRrOGE59VfbuZUfwFujg=="], + + "@aws-sdk/core": ["@aws-sdk/core@3.978.1", "", { "dependencies": { "@aws-sdk/types": "^3.974.6", "@aws-sdk/xml-builder": "^3.972.41", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.35.0", "@smithy/signature-v4": "^5.7.3", "@smithy/types": "^4.19.0", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-LbY9aGsEiznDWmUc30Nwv3aIX/+dbwTx8KfS0yOC3NPYMO+O91e6jkT1azf34FwjOndq8/Q+RcVVZz5xnerwdg=="], + + "@aws-sdk/credential-provider-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.972.71", "", { "dependencies": { "@aws-sdk/nested-clients": "^3.997.46", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-rsxsi8tF3vMGdWdaHQNXceHBdb49442yR2Pe08K+Phoc/yICbptdsHwL25Wf0z5+hjhSS5a+hDJHP7Xul4zvHQ=="], + + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.72", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-xTKO/FWJPozTIXbozVnVGoNBhaGba8TBcx+KyUjRVeOlXE+dUc7GTR1cLvu0uTdIdmemzaFbqqCshXeZA1fZew=="], + + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.74", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/fetch-http-handler": "^5.8.0", "@smithy/node-http-handler": "^4.12.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-u91E/hT8f4d1xy0Jl7VG4nVKJ3lxbrZkoBTeSVoJdWBiSEUMwMS/9+e0H/aJVQV//Lt5wuzP+E69v4aRSsNTmw=="], + + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.17", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/credential-provider-env": "^3.972.72", "@aws-sdk/credential-provider-http": "^3.972.74", "@aws-sdk/credential-provider-login": "^3.972.79", "@aws-sdk/credential-provider-process": "^3.972.72", "@aws-sdk/credential-provider-sso": "^3.973.16", "@aws-sdk/credential-provider-web-identity": "^3.972.78", "@aws-sdk/nested-clients": "^3.997.46", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/credential-provider-imds": "^4.5.2", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-ged4KXdBkvIC81bLvNHHuQKdKak/VXhQTR1NWYTTqW0474nlmsxy9O/vlgTIohDDWH3xpBdtVMZRyjb+DnocDA=="], + + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.79", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/nested-clients": "^3.997.46", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-L+Z85anONJd8MaiuraO4wRxATCdEejBZ3K3eymzWI5JPXa9sOS9CkIm72PBKqXKX+Z9p9NGMX5AIMXm0LEflgw=="], + + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.84", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.72", "@aws-sdk/credential-provider-http": "^3.972.74", "@aws-sdk/credential-provider-ini": "^3.973.17", "@aws-sdk/credential-provider-process": "^3.972.72", "@aws-sdk/credential-provider-sso": "^3.973.16", "@aws-sdk/credential-provider-web-identity": "^3.972.78", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/credential-provider-imds": "^4.5.2", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-oHt854odINVwzwsh+c5x69j0ajm4DbqqqVJ+O1ECsCIZeMDAbzFpXItaqP7UZstJj/ATdTk/KFSH0LaNAgV+kA=="], + + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.72", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-rLIp2xbMjX/k9/od7APpqq1ZgXXnV0pOL1Th3ZsL8Wu0TRtBsDTVS8iPqcfRFcHakFxPvR04OSTv2ka2qOb/2A=="], + + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.16", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/nested-clients": "^3.997.46", "@aws-sdk/token-providers": "3.1138.0", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-IGihaJfFZYacJJr/odqILCoK7W/mvrZ7cuK7ECn3sAu4vLC6u0V8bS7mCGbdugJ8Aum2tnvqmx0F2MRFp2rn9g=="], + + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.78", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/nested-clients": "^3.997.46", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-/y9WvNtlcPBGLR0qc1a+9J/xtYZfVczvLUOuXaVWylzttH7ewsxwHtjmiJSolNrVSDorIxHGHMU61CbonRkmwA=="], + + "@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.1057.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.1057.0", "@aws-sdk/core": "^3.974.15", "@aws-sdk/credential-provider-cognito-identity": "^3.972.38", "@aws-sdk/credential-provider-env": "^3.972.41", "@aws-sdk/credential-provider-http": "^3.972.43", "@aws-sdk/credential-provider-ini": "^3.972.46", "@aws-sdk/credential-provider-login": "^3.972.45", "@aws-sdk/credential-provider-node": "^3.972.47", "@aws-sdk/credential-provider-process": "^3.972.41", "@aws-sdk/credential-provider-sso": "^3.972.45", "@aws-sdk/credential-provider-web-identity": "^3.972.45", "@aws-sdk/nested-clients": "^3.997.13", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.5", "@smithy/credential-provider-imds": "^4.3.6", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-rbrEHtz11g0kxsSkYr3fx2HABNNblp4AhB2MgPvJHgYOWfJ2eBviU7Mvoaef0PW8QH6lbZDfJcnM7eKvtvz3sw=="], + + "@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.46", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/signature-v4-multi-region": "^3.996.47", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/fetch-http-handler": "^5.8.0", "@smithy/node-http-handler": "^4.12.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-oRxtBcka/JGHGs9l9p9IVajGoTP8vTPmoAzdHGy4Qcy9P5vPnDf6nhIeM/COQNY9k/OahImTRaLkHftoXvfcmQ=="], + + "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.47", "", { "dependencies": { "@aws-sdk/types": "^3.974.6", "@smithy/signature-v4": "^5.7.3", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-Zk08macMvQTHzQJCLJVkOlviVoqwYMrpXv4lmLN7b7sAbiMoOK7Go0NYdR5UeF+MW8LIbRmwrNy9u/5VvX1U5g=="], + + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1138.0", "", { "dependencies": { "@aws-sdk/core": "^3.978.1", "@aws-sdk/nested-clients": "^3.997.46", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-GpyAr0DD63YOEmYFM6Df+gJuIgC92MMTiBK4FTKfxii5MJ9ge20epR7LyroulscYlG89J+ZB2ivFDPjvfQhzdw=="], + + "@aws-sdk/types": ["@aws-sdk/types@3.974.6", "", { "dependencies": { "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-v/clNZzZnDxGyvpHMOGpJKVXFAExJzUNAAjaWGdcx8QAcXLGwTaOkw33p5SHAi0YAioK32xB3hWwOekRVfmfKg=="], + + "@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.10", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-ycwH6Zd2GhuSqdXX9ihbCjeGTB6xOJs+O3+Jb8/zDG9978XU80qs75dfkPJRMNKe5MvBZPuNeFpd4JZKPoUF4g=="], + + "@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.41", "", { "dependencies": { "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-ctjVSyCMegrWfXlx6VqzSBFI6UqmQ5ZlnfMhdLIiWmhoH8UAQxSCP5N3OpG7X3k4LnS7ou74C4mt20+bfTW2aQ=="], + + "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.3.0", "", {}, "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ=="], + + "@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.112", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.112" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-OTRv1DxTHUmnakgJ6XVM8wVgF1KgZH4UXnOemwSLUwUjXO+RCikzF8oR/rlVmOGq81KtQzj1URM4M4nchlQOuQ=="], + + "@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="], + + "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="], + + "@gar/promise-retry": ["@gar/promise-retry@1.0.3", "", {}, "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA=="], + + "@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", "strip-ansi": "^7.0.1", "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", "wrap-ansi": "^8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="], + + "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + + "@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", {}, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="], + + "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="], + + "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="], + + "@msgpackr-extract/msgpackr-extract-linux-arm": ["@msgpackr-extract/msgpackr-extract-linux-arm@3.0.4", "", { "os": "linux", "cpu": "arm" }, "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw=="], + + "@msgpackr-extract/msgpackr-extract-linux-arm64": ["@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw=="], + + "@msgpackr-extract/msgpackr-extract-linux-x64": ["@msgpackr-extract/msgpackr-extract-linux-x64@3.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ=="], + + "@msgpackr-extract/msgpackr-extract-win32-x64": ["@msgpackr-extract/msgpackr-extract-win32-x64@3.0.4", "", { "os": "win32", "cpu": "x64" }, "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ=="], + + "@npmcli/agent": ["@npmcli/agent@4.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", "lru-cache": "^11.2.1", "socks-proxy-agent": "^8.0.3" } }, "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg=="], + + "@npmcli/arborist": ["@npmcli/arborist@9.4.0", "", { "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/fs": "^5.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/map-workspaces": "^5.0.0", "@npmcli/metavuln-calculator": "^9.0.2", "@npmcli/name-from-folder": "^4.0.0", "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/query": "^5.0.0", "@npmcli/redact": "^4.0.0", "@npmcli/run-script": "^10.0.0", "bin-links": "^6.0.0", "cacache": "^20.0.1", "common-ancestor-path": "^2.0.0", "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", "lru-cache": "^11.2.1", "minimatch": "^10.0.3", "nopt": "^9.0.0", "npm-install-checks": "^8.0.0", "npm-package-arg": "^13.0.0", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "pacote": "^21.0.2", "parse-conflict-json": "^5.0.1", "proc-log": "^6.0.0", "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", "promise-call-limit": "^3.0.1", "semver": "^7.3.7", "ssri": "^13.0.0", "treeverse": "^3.0.0", "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" } }, "sha512-4Bm8hNixJG/sii1PMnag0V9i/sGOX9VRzFrUiZMSBJpGlLR38f+Btl85d07G9GL56xO0l0OZjvrGNYsDYp0xKA=="], + + "@npmcli/config": ["@npmcli/config@10.8.1", "", { "dependencies": { "@npmcli/map-workspaces": "^5.0.0", "@npmcli/package-json": "^7.0.0", "ci-info": "^4.0.0", "ini": "^6.0.0", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "walk-up-path": "^4.0.0" } }, "sha512-MAYk9IlIGiyC0c9fnjdBSQfIFPZT0g1MfeSiD1UXTq2zJOLX55jS9/sETJHqw/7LN18JjITrhYfgCfapbmZHiQ=="], + + "@npmcli/fs": ["@npmcli/fs@5.0.0", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og=="], + + "@npmcli/git": ["@npmcli/git@7.0.2", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/promise-spawn": "^9.0.0", "ini": "^6.0.0", "lru-cache": "^11.2.1", "npm-pick-manifest": "^11.0.1", "proc-log": "^6.0.0", "semver": "^7.3.5", "which": "^6.0.0" } }, "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg=="], + + "@npmcli/installed-package-contents": ["@npmcli/installed-package-contents@4.0.0", "", { "dependencies": { "npm-bundled": "^5.0.0", "npm-normalize-package-bin": "^5.0.0" }, "bin": { "installed-package-contents": "bin/index.js" } }, "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA=="], + + "@npmcli/map-workspaces": ["@npmcli/map-workspaces@5.0.3", "", { "dependencies": { "@npmcli/name-from-folder": "^4.0.0", "@npmcli/package-json": "^7.0.0", "glob": "^13.0.0", "minimatch": "^10.0.3" } }, "sha512-o2grssXo1e774E5OtEwwrgoszYRh0lqkJH+Pb9r78UcqdGJRDRfhpM8DvZPjzNLLNYeD/rNbjOKM3Ss5UABROw=="], + + "@npmcli/metavuln-calculator": ["@npmcli/metavuln-calculator@9.0.3", "", { "dependencies": { "cacache": "^20.0.0", "json-parse-even-better-errors": "^5.0.0", "pacote": "^21.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5" } }, "sha512-94GLSYhLXF2t2LAC7pDwLaM4uCARzxShyAQKsirmlNcpidH89VA4/+K1LbJmRMgz5gy65E/QBBWQdUvGLe2Frg=="], + + "@npmcli/name-from-folder": ["@npmcli/name-from-folder@4.0.0", "", {}, "sha512-qfrhVlOSqmKM8i6rkNdZzABj8MKEITGFAY+4teqBziksCQAOLutiAxM1wY2BKEd8KjUSpWmWCYxvXr0y4VTlPg=="], + + "@npmcli/node-gyp": ["@npmcli/node-gyp@5.0.0", "", {}, "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ=="], + + "@npmcli/package-json": ["@npmcli/package-json@7.0.5", "", { "dependencies": { "@npmcli/git": "^7.0.0", "glob": "^13.0.0", "hosted-git-info": "^9.0.0", "json-parse-even-better-errors": "^5.0.0", "proc-log": "^6.0.0", "semver": "^7.5.3", "spdx-expression-parse": "^4.0.0" } }, "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ=="], + + "@npmcli/promise-spawn": ["@npmcli/promise-spawn@9.0.1", "", { "dependencies": { "which": "^6.0.0" } }, "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q=="], + + "@npmcli/query": ["@npmcli/query@5.0.0", "", { "dependencies": { "postcss-selector-parser": "^7.0.0" } }, "sha512-8TZWfTQOsODpLqo9SVhVjHovmKXNpevHU0gO9e+y4V4fRIOneiXy0u0sMP9LmS71XivrEWfZWg50ReH4WRT4aQ=="], + + "@npmcli/redact": ["@npmcli/redact@4.0.0", "", {}, "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q=="], + + "@npmcli/run-script": ["@npmcli/run-script@10.0.4", "", { "dependencies": { "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "node-gyp": "^12.1.0", "proc-log": "^6.0.0" } }, "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@1.0.191", "", { "dependencies": { "@opencode-ai/sdk": "1.0.191", "zod": "4.1.8" } }, "sha512-+Z83g4uwRM+Qed5bV/HJ9KEA4FOPEOKZgTcyIvl0lVu++VYwPXydy1+YyW+/IRp17Ghz/xF7zWL+pBh2XlT9xQ=="], "@opencode-ai/sdk": ["@opencode-ai/sdk@1.0.191", "", {}, "sha512-UjbwaxdrP8XFbMcCCy4FfWbGrY1Kz/6wzdg34ASCVlXA/FxfWw7cFhM9oPKnwmR7HyGY7nq/y4Ywb0yW9TAwEA=="], + "@opencode/ai": ["@opencode/ai@2.0.15", "", { "dependencies": { "@aws-sdk/credential-providers": "3.1057.0", "@opencode/schema": "2.0.15", "@smithy/eventstream-codec": "4.2.14", "@smithy/util-utf8": "4.2.2", "aws4fetch": "1.0.20", "effect": "4.0.0-rc.112", "google-auth-library": "10.5.0" } }, "sha512-dY3HG6bp+UMJOi+m1nfzvQaTPpCSmMNDswAOLQq/MJghGrD54WrcEC4IhAQ1hJY7b/hhQYOzPAMeJsvF4aRYYQ=="], + + "@opencode/client": ["@opencode/client@2.0.15", "", { "dependencies": { "@opencode/protocol": "2.0.15", "@opencode/schema": "2.0.15" }, "peerDependencies": { "effect": "4.0.0-rc.112", "solid-js": ">=1.9.0" }, "optionalPeers": ["effect", "solid-js"] }, "sha512-Lu3Pb6Z/lJ797VryQrsdqEgVBXjtYZWOxLNZKyBUDgXhO/GpzOpXi1H1Uo4g+qWrH8LwUISDBdxHHOWJy5HcqQ=="], + + "@opencode/plugin": ["@opencode/plugin@2.0.15", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode/ai": "2.0.15", "@opencode/client": "2.0.15", "@opencode/protocol": "2.0.15", "@opencode/schema": "2.0.15", "@opencode/util": "2.0.15", "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112", "zod": "4.1.8" }, "peerDependencies": { "@opencode/theme": "2.0.15", "@opentui/core": ">=0.5.10", "@opentui/solid": ">=0.5.10", "solid-js": ">=1.9.0" }, "optionalPeers": ["@opencode/theme", "@opentui/core", "@opentui/solid", "solid-js"] }, "sha512-TsSXd2g/433De7ViY+5d/tlLtkZCSmYKo8ScnhtcmPVoM/U5ptQDFXEXx5psTlAfkKcISJh+5vMSOe4u3uCqUQ=="], + + "@opencode/protocol": ["@opencode/protocol@2.0.15", "", { "dependencies": { "@opencode/schema": "2.0.15", "effect": "4.0.0-rc.112" } }, "sha512-fFi3VYdgNQzT4TswfKGul7DzseOyhA4b/hE/elUe3xxm5iki4tP/pjT8CU3rRWX8sK/75ICr36NAUhSayFtJuw=="], + + "@opencode/schema": ["@opencode/schema@2.0.15", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112" } }, "sha512-D0JDwF4uTNmFA2MyiSnZ5DlT/t2PF1EEwVbRPulB/Ppcss/z5Fcn6VybHrapki2bKDVQu1Mnn8zBW3G6KP5I6g=="], + + "@opencode/util": ["@opencode/util@2.0.15", "", { "dependencies": { "@effect/opentelemetry": "4.0.0-rc.112", "@effect/platform-node": "4.0.0-rc.112", "@effect/platform-node-shared": "4.0.0-rc.112", "@npmcli/arborist": "9.4.0", "@npmcli/config": "10.8.1", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.6.1", "@opentelemetry/exporter-trace-otlp-http": "0.214.0", "@opentelemetry/sdk-trace-base": "2.6.1", "@opentelemetry/sdk-trace-node": "2.6.1", "cross-spawn": "7.0.6", "effect": "4.0.0-rc.112", "glob": "13.0.5", "mime-types": "3.0.2", "minimatch": "10.2.5", "npm-package-arg": "13.0.2", "pacote": "21.5.1" } }, "sha512-s0Z+2rxb+2Tif+ZV1EvTiGQ0tRiemIZq3WOOjBw2XPBSBt2Sfv9rWXJhTzSpkOZucfTyymuIVXslXPGFF7aaQA=="], + + "@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="], + + "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.214.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-40lSJeqYO8Uz2Yj7u94/SJWE/wONa7rmMKjI1ZcIjgf3MHNHv1OZUCrCETGuaRF62d5pQD1wKIW+L4lmSMTzZA=="], + + "@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.6.1", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-XHzhwRNkBpeP8Fs/qjGrAf9r9PRv67wkJQ/7ZPaBQQ68DYlTBBx5MF9LvPx7mhuXcDessKK2b+DcxqwpgkcivQ=="], + + "@opentelemetry/core": ["@opentelemetry/core@2.6.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g=="], + + "@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.214.0", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/otlp-exporter-base": "0.214.0", "@opentelemetry/otlp-transformer": "0.214.0", "@opentelemetry/resources": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-kIN8nTBMgV2hXzV/a20BCFilPZdAIMYYJGSgfMMRm/Xa+07y5hRDS2Vm12A/z8Cdu3Sq++ZvJfElokX2rkgGgw=="], + + "@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.214.0", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/otlp-transformer": "0.214.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-u1Gdv0/E9wP+apqWf7Wv2npXmgJtxsW2XL0TEv9FZloTZRuMBKmu8cYVXwS4Hm3q/f/3FuCnPTgiwYvIqRSpRg=="], + + "@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/sdk-logs": "0.214.0", "@opentelemetry/sdk-metrics": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1", "protobufjs": "^7.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-DSaYcuBRh6uozfsWN3R8HsN0yDhCuWP7tOFdkUOVaWD1KVJg8m4qiLUsg/tNhTLS9HUYUcwNpwL2eroLtsZZ/w=="], + + "@opentelemetry/resources": ["@opentelemetry/resources@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-lID/vxSuKWXM55XhAKNoYXu9Cutoq5hFdkbTdI/zDKQktXzcWBVhNsOkiZFTMU9UtEWuGRNe0HUgmsFldIdxVA=="], + + "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.214.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.214.0", "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-zf6acnScjhsaBUU22zXZ/sLWim1dfhUAbGXdMmHmNG3LfBnQ3DKsOCITb2IZwoUsNNMTogqFKBnlIPPftUgGwA=="], + + "@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-9t9hJHX15meBy2NmTJxL+NJfXmnausR2xUDvE19XQce0Qi/GBtDGamU8nS1RMbdgDmhgpm3VaOu2+fiS/SfTpQ=="], + + "@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.6.1", "", { "dependencies": { "@opentelemetry/core": "2.6.1", "@opentelemetry/resources": "2.6.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-r86ut4T1e8vNwB35CqCcKd45yzqH6/6Wzvpk2/cZB8PsPLlZFTvrh8yfOS3CYZYcUmAx4hHTZJ8AO8Dj8nrdhw=="], + + "@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.6.1", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.6.1", "@opentelemetry/core": "2.6.1", "@opentelemetry/sdk-trace-base": "2.6.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-Hh2i4FwHWRFhnO2Q/p6svMxy8MPsNCG0uuzUY3glqm0rwM0nQvbTO1dXSp9OqQoTKXcQzaz9q1f65fsurmOhNw=="], + + "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="], + + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], + + "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], + + "@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="], + + "@protobufjs/codegen": ["@protobufjs/codegen@2.0.5", "", {}, "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="], + + "@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.1", "", {}, "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg=="], + + "@protobufjs/fetch": ["@protobufjs/fetch@1.1.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1" } }, "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw=="], + + "@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="], + + "@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="], + + "@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="], + + "@protobufjs/utf8": ["@protobufjs/utf8@1.1.2", "", {}, "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug=="], + + "@redis/bloom": ["@redis/bloom@6.2.1", "", { "peerDependencies": { "@redis/client": "^6.2.1" } }, "sha512-huQgNLaCIZfQ9SeLn4q9124uOUd8HbZDYHwwUzNcRgHqCHiHKl2dDxMqJCeWh8cMqZAoWuHR8XnWbDMIf+o7ag=="], + + "@redis/client": ["@redis/client@6.2.1", "", { "dependencies": { "cluster-key-slot": "1.1.2" }, "peerDependencies": { "@node-rs/xxhash": "^1.1.0", "@opentelemetry/api": ">=1 <2" }, "optionalPeers": ["@node-rs/xxhash", "@opentelemetry/api"] }, "sha512-LzxBY7SIBvvJiyCgcaJZZakE3fJrZZ++i24+EDW9fKpCl68D35uJcKFpZZwCfOoG9WZTbyZlMzMeM0gtOAMU9Q=="], + + "@redis/json": ["@redis/json@6.2.1", "", { "peerDependencies": { "@redis/client": "^6.2.1" } }, "sha512-AFIUJ8Gj0DaaSBHYuSt8+O0oYWM+50OK1c0OmodB7XERIA8+BbyV3O4v76f9iccWasd1/7qjfZTpuzexUaZtrQ=="], + + "@redis/search": ["@redis/search@6.2.1", "", { "peerDependencies": { "@redis/client": "^6.2.1" } }, "sha512-2vfOAOyYFE7UUw3sBBlkqqruBtOUS4HRY5MtW4hp83llrwvtrTE4r22CEqXddlV+54zkLxBE4nmsIJ/dpezQrQ=="], + + "@redis/time-series": ["@redis/time-series@6.2.1", "", { "peerDependencies": { "@redis/client": "^6.2.1" } }, "sha512-kiYniph04dJOole+L359B6C9E+jYS2uDP7hca6Onj0xF38ZIpyxARO0Iq0W4ZRn1e8Q6vqW00QFZVSMRA/2Ijw=="], + + "@sigstore/bundle": ["@sigstore/bundle@4.0.0", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A=="], + + "@sigstore/core": ["@sigstore/core@3.2.1", "", {}, "sha512-qRsxPnCrbC/puegGxKuynfnxgLiHqWStrSjxkoB4YKqq3Z3s4cyZyj42ZdWFAEblNP65C+rBH8EuREHIXoi83g=="], + + "@sigstore/protobuf-specs": ["@sigstore/protobuf-specs@0.5.2", "", {}, "sha512-SQqvFMt4V78fdjcDdYX6HbiVSOR4QK3ZgwCa2KOsopAgPIHy1rU5UDUmzLl02r5oyyaYcYHR1hpwDRk/yUe+Mw=="], + + "@sigstore/sign": ["@sigstore/sign@4.1.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.2", "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.2.0", "@sigstore/protobuf-specs": "^0.5.0", "make-fetch-happen": "^15.0.4", "proc-log": "^6.1.0" } }, "sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ=="], + + "@sigstore/tuf": ["@sigstore/tuf@4.0.2", "", { "dependencies": { "@sigstore/protobuf-specs": "^0.5.0", "tuf-js": "^4.1.0" } }, "sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ=="], + + "@sigstore/verify": ["@sigstore/verify@3.1.1", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0" } }, "sha512-qv7+G3J2cc6wwFj3yKvXOamzqhMwSk1ogPGmhpS8iXllcPrJaIIBA+4HbttlHVu1pqWTdmaCH/WE7UOC51kdoA=="], + + "@smithy/core": ["@smithy/core@3.35.0", "", { "dependencies": { "@smithy/types": "^4.19.0", "tslib": "^2.6.2" } }, "sha512-zRMhfkByhT2snNdr1si24vJitU6Cr9ix2MikUfWmkAgp4jrNP0GcKSP5YvwQ+TlI8AZXER5QOGJn3JsVtSD9/A=="], + + "@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.5.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg=="], + + "@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.2.14", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.1", "@smithy/util-hex-encoding": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw=="], + + "@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.8.0", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.18.0", "tslib": "^2.6.2" } }, "sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA=="], + + "@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="], + + "@smithy/node-http-handler": ["@smithy/node-http-handler@4.12.1", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.18.0", "tslib": "^2.6.2" } }, "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw=="], + + "@smithy/signature-v4": ["@smithy/signature-v4@5.7.3", "", { "dependencies": { "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow=="], + + "@smithy/types": ["@smithy/types@4.19.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-r7jh49VJxGerfAcTQA6gXcKc+98zOp/tqRwzYjgOE+iSQsP6cEU1hq2QzbuipmP68QtYdY9wKEhiCQZIzHgZ4Q=="], + + "@smithy/util-buffer-from": ["@smithy/util-buffer-from@4.5.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "tslib": "^2.6.2" } }, "sha512-nxu3SgmAw9JXT2CtkU0m/XNLWpP9MsaBx1zAGAypCbYj15tIFlmcYwpF+Oh18le83d+IM9PT7ENdXnE4C+d5mA=="], + + "@smithy/util-hex-encoding": ["@smithy/util-hex-encoding@4.5.2", "", { "dependencies": { "@smithy/core": "^3.33.2", "tslib": "^2.6.2" } }, "sha512-iq+cW3mAb7vfcxEEpYi3zXKpDtbrIFyanWjQl4zBq4seWD4OSxXDWSfespZxenX6aEaighn+NR3u1nU1DSvs3w=="], + + "@smithy/util-utf8": ["@smithy/util-utf8@4.2.2", "", { "dependencies": { "@smithy/util-buffer-from": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@tufjs/canonical-json": ["@tufjs/canonical-json@2.0.0", "", {}, "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA=="], + + "@tufjs/models": ["@tufjs/models@4.1.0", "", { "dependencies": { "@tufjs/canonical-json": "2.0.0", "minimatch": "^10.1.1" } }, "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww=="], + "@types/bun": ["@types/bun@1.3.5", "", { "dependencies": { "bun-types": "1.3.5" } }, "sha512-RnygCqNrd3srIPEWBd5LFeUYG7plCoH2Yw9WaZGyNmdTEei+gWaHqydbaIRkIkcbXwhBT94q78QljxN0Sk838w=="], "@types/node": ["@types/node@25.0.3", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], + + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], + + "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], + + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], + + "bin-links": ["bin-links@6.0.2", "", { "dependencies": { "cmd-shim": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "proc-log": "^6.0.0", "read-cmd-shim": "^6.0.0", "write-file-atomic": "^7.0.0" } }, "sha512-frE1t78WOwJ45PKV2cF2tNPjTcs9L1J9s6VkrV59wanRP4GlaomuxYPVma7BwthMg8WnfSory4w5PTE6FZZ81w=="], + + "bowser": ["bowser@2.14.1", "", {}, "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg=="], + + "brace-expansion": ["brace-expansion@5.0.12", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ=="], + + "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], + "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], + "cacache": ["cacache@20.0.4", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0" } }, "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA=="], + + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + + "cluster-key-slot": ["cluster-key-slot@1.1.2", "", {}, "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA=="], + + "cmd-shim": ["cmd-shim@8.0.0", "", {}, "sha512-Jk/BK6NCapZ58BKUxlSI+ouKRbjH1NLZCgJkYoab+vEHUY3f6OzpNBN9u7HFSv9J6TRDGs4PLOHezoKGaFRSCA=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "common-ancestor-path": ["common-ancestor-path@2.0.0", "", {}, "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng=="], + + "content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + + "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], + + "effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "fast-check": ["fast-check@4.10.2", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-iK2f+YrcmoeGqk6fA0ea2bptcu/itMIm4NfEozq6N25+aG6h7s5HZbB/k1aV7b5w5sFLMCbbtRUsTVR+BgC3xw=="], + + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], + + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], + + "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], + + "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], + + "gaxios": ["gaxios@7.3.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ=="], + + "gcp-metadata": ["gcp-metadata@8.1.4", "", { "dependencies": { "gaxios": "7.1.3", "google-logging-utils": "1.1.3", "json-bigint": "^1.0.0" } }, "sha512-iJ9KMsiu+xKtNRX0PmGLSaIU3bUBAyzWTyqKemKPzNPsmmsBCQYmlNg+brEbES7IHSXtdVwzBPzx1vz3FAaipw=="], + + "glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], + + "google-auth-library": ["google-auth-library@10.5.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.0.0", "gcp-metadata": "^8.0.0", "google-logging-utils": "^1.0.0", "gtoken": "^8.0.0", "jws": "^4.0.0" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="], + + "google-logging-utils": ["google-logging-utils@1.2.0", "", {}, "sha512-WE9av4wKDZgRjBwgVUabocx8T6/7o3Ca1Fat46FXDhXVAFibzNadedcOXrdgd1Kzmk8tsk/9ZH89Wyf/SqeZ3A=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="], + + "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], + + "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], + + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + + "iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="], + + "ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="], + + "ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], + + "ip-address": ["ip-address@10.7.2", "", {}, "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + + "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@5.0.0", "", {}, "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ=="], + + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], + + "json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="], + + "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], + + "jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="], + + "just-diff": ["just-diff@6.0.2", "", {}, "sha512-S59eriX5u3/QhMNq3v/gm8Kd0w8OS6Tz2FS1NG4blv+z0MuQcBRJyFWjdovM0Rad4/P4aUPFtnkNjMjyMlMSYA=="], + + "just-diff-apply": ["just-diff-apply@5.5.0", "", {}, "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw=="], + + "jwa": ["jwa@2.0.1", "", { "dependencies": { "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg=="], + + "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], + + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], + + "lru-cache": ["lru-cache@11.5.3", "", {}, "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg=="], + + "make-fetch-happen": ["make-fetch-happen@15.0.6", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", "ssri": "^13.0.0" } }, "sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw=="], + + "mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + + "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "minipass-collect": ["minipass-collect@2.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw=="], + + "minipass-fetch": ["minipass-fetch@5.0.2", "", { "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^2.0.0", "minizlib": "^3.0.1" }, "optionalDependencies": { "iconv-lite": "^0.7.2" } }, "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ=="], + + "minipass-flush": ["minipass-flush@1.0.7", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA=="], + + "minipass-pipeline": ["minipass-pipeline@1.2.4", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A=="], + + "minipass-sized": ["minipass-sized@2.0.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA=="], + + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "msgpackr": ["msgpackr@2.1.0", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-p/pBCVO63CsvvpkomUnNNag6+n38rULuDA6HHe70o2gtC8ODI52foF/4ko2qQcp6OiErJXTmrZeXmsGGHsIQNQ=="], + + "msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], + + "negotiator": ["negotiator@1.1.0", "", { "dependencies": { "content-type": "^2.1.0" } }, "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg=="], + + "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], + + "node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "^4.0.0", "fetch-blob": "^3.1.4", "formdata-polyfill": "^4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="], + + "node-gyp": ["node-gyp@12.4.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.4", "tinyglobby": "^0.2.12", "undici": "^6.25.0", "which": "^6.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw=="], + + "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], + + "nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], + + "npm-bundled": ["npm-bundled@5.0.0", "", { "dependencies": { "npm-normalize-package-bin": "^5.0.0" } }, "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw=="], + + "npm-install-checks": ["npm-install-checks@8.0.0", "", { "dependencies": { "semver": "^7.1.1" } }, "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA=="], + + "npm-normalize-package-bin": ["npm-normalize-package-bin@5.0.0", "", {}, "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag=="], + + "npm-package-arg": ["npm-package-arg@13.0.2", "", { "dependencies": { "hosted-git-info": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "validate-npm-package-name": "^7.0.0" } }, "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA=="], + + "npm-packlist": ["npm-packlist@10.0.4", "", { "dependencies": { "ignore-walk": "^8.0.0", "proc-log": "^6.0.0" } }, "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng=="], + + "npm-pick-manifest": ["npm-pick-manifest@11.0.3", "", { "dependencies": { "npm-install-checks": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "npm-package-arg": "^13.0.0", "semver": "^7.3.5" } }, "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ=="], + + "npm-registry-fetch": ["npm-registry-fetch@19.1.1", "", { "dependencies": { "@npmcli/redact": "^4.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^13.0.0", "proc-log": "^6.0.0" } }, "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw=="], + + "p-map": ["p-map@7.0.8", "", {}, "sha512-MitaVsCuCFIvOLLPIU7NnfrZvS9H9h7kwMUkDo+T2pEISaJD48IV9S8iIdXB7PsvvdxyYcsSTTrr90XKsbulNw=="], + + "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], + + "pacote": ["pacote@21.5.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": { "pacote": "bin/index.js" } }, "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg=="], + + "parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + + "picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="], + + "postcss-selector-parser": ["postcss-selector-parser@7.1.6", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw=="], + + "proc-log": ["proc-log@6.1.0", "", {}, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="], + + "proggy": ["proggy@4.0.0", "", {}, "sha512-MbA4R+WQT76ZBm/5JUpV9yqcJt92175+Y0Bodg3HgiXzrmKu7Ggq+bpn6y6wHH+gN9NcyKn3yg1+d47VaKwNAQ=="], + + "promise-all-reject-late": ["promise-all-reject-late@1.0.1", "", {}, "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw=="], + + "promise-call-limit": ["promise-call-limit@3.0.2", "", {}, "sha512-mRPQO2T1QQVw11E7+UdCJu7S61eJVWknzml9sC1heAdj1jxl0fWMBypIt9ZOcLFf8FkG995ZD7RnVk7HH72fZw=="], + + "protobufjs": ["protobufjs@7.6.6", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg=="], + + "pure-rand": ["pure-rand@8.4.2", "", {}, "sha512-vvuOGgcuPJAirlHvuQw1TrOiw7ptaIXXmIbNuiNOY6lNGJJH49PQ1Kj4nd783nPdQhQdicgOjVI2yI/9BD6/Ng=="], + + "read-cmd-shim": ["read-cmd-shim@6.0.0", "", {}, "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A=="], + + "redis": ["redis@6.2.1", "", { "dependencies": { "@redis/bloom": "6.2.1", "@redis/client": "6.2.1", "@redis/json": "6.2.1", "@redis/search": "6.2.1", "@redis/time-series": "6.2.1" } }, "sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg=="], + + "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="], + + "sigstore": ["sigstore@4.1.1", "", { "dependencies": { "@sigstore/bundle": "^4.0.0", "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0", "@sigstore/sign": "^4.1.1", "@sigstore/tuf": "^4.0.2", "@sigstore/verify": "^3.1.1" } }, "sha512-endqECJkfhozrXMK5ngu/UAA0xVcVEFdnHJCElGaExypjW+HK5i6zu3NteLoaX/iFbRUbC3+DjttQs0GARr+5w=="], + + "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + + "socks": ["socks@2.8.10", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ=="], + + "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "spdx-expression-parse": ["spdx-expression-parse@4.0.0", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.24", "", {}, "sha512-cLS9TtWkIQFyLkJ3/5aFQAOHOSKTlOs/7WDut/XPSdjom1fJhUdkepeJAKXa9Y05+FabHd0sti+Et559vDtkpQ=="], + + "ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="], + + "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + + "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "supermemory": ["supermemory@4.0.0", "", {}, "sha512-xMN05PQ8kTv8DuXa2qf8h/9LaRI7v1Kz3Tutt97JPq+PzhGabKLv5YVbSgqHiPX5yXcSUBVBNYPPbhAQMF6GYQ=="], + "tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="], + + "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], + + "treeverse": ["treeverse@3.0.0", "", {}, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tuf-js": ["tuf-js@4.1.0", "", { "dependencies": { "@tufjs/models": "4.1.0", "debug": "^4.4.3", "make-fetch-happen": "^15.0.1" } }, "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "undici": ["undici@8.11.0", "", {}, "sha512-AdzuGcAkzhbha3GgCSoUBx2P0quwym6qdFNCQz/fDGZc8w9XJ741wHUbt2kTmfPz+ZIOMkySFkiY7RXmiDDC8w=="], + "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", {}, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="], + + "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], + + "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "wrap-ansi-cjs": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "write-file-atomic": ["write-file-atomic@7.0.1", "", { "dependencies": { "signal-exit": "^4.0.1" } }, "sha512-OTIk8iR8/aCRWBqvxrzxR0hgxWpnYBblY1S5hDWBQfk/VFmJwzmJgQFN3WsoUKHISv2eAwe+PpbUzyL1CKTLXg=="], + + "ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="], + + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], + + "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + + "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + + "@npmcli/git/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + + "@npmcli/promise-spawn/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + + "gcp-metadata/gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="], + + "gcp-metadata/google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], + + "minipass-flush/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + + "node-gyp/undici": ["undici@6.28.1", "", {}, "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA=="], + + "node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + + "rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + + "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "wrap-ansi-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "@aws-crypto/sha256-browser/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + + "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + + "@npmcli/git/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + + "@npmcli/promise-spawn/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + + "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "node-gyp/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + + "rimraf/glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], + + "rimraf/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "string-width-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "wrap-ansi-cjs/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.1.7", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g=="], + + "rimraf/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], } } diff --git a/package.json b/package.json index e35bd03..3465502 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,57 @@ { "name": "opencode-supermemory", - "version": "2.0.14", + "version": "2.0.15", "description": "OpenCode plugin that gives coding agents persistent memory using Supermemory", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + }, + "./server": { + "types": "./dist/server.d.ts", + "import": "./dist/server.js", + "default": "./dist/server.js" + }, + "./tui": { + "types": "./dist/tui.d.ts", + "import": "./dist/tui.js", + "default": "./dist/tui.js" + }, + "./rpc": { + "types": "./dist/rpc.d.ts", + "import": "./dist/rpc.js", + "default": "./dist/rpc.js" + }, + "./v2": { + "types": "./dist/v2/index.d.ts", + "import": "./dist/v2/index.js", + "default": "./dist/v2/index.js" + }, + "./package.json": "./package.json" + }, "bin": { "opencode-supermemory": "./dist/cli.js" }, "scripts": { "generate:version": "node scripts/sync-version.mjs", - "build": "node scripts/sync-version.mjs && bun build ./src/index.ts --outdir ./dist --target node && bun build ./src/cli.ts --outfile ./dist/cli.js --target node && tsc --emitDeclarationOnly", + "build": "node scripts/sync-version.mjs && bun build ./src/index.ts ./src/server.ts ./src/tui.ts ./src/rpc.ts --outdir ./dist --target node && bun build ./src/v2/index.ts --outfile ./dist/v2/index.js --target node && bun build ./src/cli.ts --outfile ./dist/cli.js --target node && tsc --emitDeclarationOnly", "dev": "tsc --watch", "typecheck": "node scripts/sync-version.mjs && tsc --noEmit", "test": "node scripts/sync-version.mjs && bun test" }, "keywords": [ + "ai", + "coding-agent", + "memory", "opencode", + "opencode-plugin", + "opencode-v2", "plugin", - "supermemory", - "memory", - "ai", - "coding-agent" + "supermemory" ], "author": "Supermemory", "license": "MIT", @@ -31,7 +61,9 @@ }, "devDependencies": { "@opencode-ai/plugin": "^1.0.162", + "@opencode/plugin": "2.0.15", "@types/bun": "latest", + "jsonc-parser": "3.3.1", "supermemory": "^4.0.0", "typescript": "^5.7.3" }, diff --git a/server.ts b/server.ts new file mode 100644 index 0000000..6706b1a --- /dev/null +++ b/server.ts @@ -0,0 +1,4 @@ +// Local-development entry for OpenCode 2. Point a config at this checkout, +// e.g. "plugins": ["/path/to/opencode-supermemory"], and OpenCode loads the +// TypeScript sources directly. The published package uses dist/server.js. +export { default } from "./src/server.ts"; diff --git a/src/cli.ts b/src/cli.ts index 4c6145f..92871ae 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -3,11 +3,16 @@ import { mkdirSync, writeFileSync, readFileSync, existsSync } from "node:fs"; import { join } from "node:path"; import { homedir } from "node:os"; import * as readline from "node:readline"; -import { stripJsoncComments } from "./services/jsonc.js"; import { startAuthFlow, clearCredentials, loadCredentials, CREDENTIALS_FILE } from "./services/auth.js"; import { CONFIG, CONFIG_FILE, SUPERMEMORY_API_KEY, getApiBaseUrl, isConfigured, writeInstallDefaults } from "./config.js"; import { SupermemoryClient } from "./services/client.js"; import { getTags } from "./services/tags.js"; +import { + editOpenCodeConfig, + readOpenCodeRegistration, + V1_PLUGIN_ENTRY, + V2_PLUGIN_ENTRY, +} from "./services/opencode-config.js"; const OPENCODE_CONFIG_DIR = join(homedir(), ".config", "opencode"); const OPENCODE_COMMAND_DIRS = [ @@ -15,7 +20,6 @@ const OPENCODE_COMMAND_DIRS = [ join(OPENCODE_CONFIG_DIR, "command"), ]; const OH_MY_OPENCODE_CONFIG = join(OPENCODE_CONFIG_DIR, "oh-my-opencode.json"); -const PLUGIN_NAME = "opencode-supermemory@latest"; const DEFAULT_CONFIG_FILE = CONFIG_FILE ?? join(OPENCODE_CONFIG_DIR, "supermemory.json"); const SUPERMEMORY_INDEX_COMMAND = `--- @@ -275,51 +279,18 @@ function findOpencodeConfig(): string | null { function addPluginToConfig(configPath: string): boolean { try { const content = readFileSync(configPath, "utf-8"); - - if (content.includes("opencode-supermemory")) { - console.log("✓ Plugin already registered in config"); - return true; - } - - const jsonContent = stripJsoncComments(content); - let config: Record; - - try { - config = JSON.parse(jsonContent); - } catch { - console.error("✗ Failed to parse config file"); - return false; - } + const result = editOpenCodeConfig(content); - const plugins = (config.plugin as string[]) || []; - plugins.push(PLUGIN_NAME); - config.plugin = plugins; - - if (configPath.endsWith(".jsonc")) { - if (content.includes('"plugin"')) { - const newContent = content.replace( - /("plugin"\s*:\s*\[)([^\]]*?)(\])/, - (_match, start, middle, end) => { - const trimmed = middle.trim(); - if (trimmed === "") { - return `${start}\n "${PLUGIN_NAME}"\n ${end}`; - } - return `${start}${middle.trimEnd()},\n "${PLUGIN_NAME}"\n ${end}`; - } - ); - writeFileSync(configPath, newContent); - } else { - const newContent = content.replace( - /^(\s*\{)/, - `$1\n "plugin": ["${PLUGIN_NAME}"],` - ); - writeFileSync(configPath, newContent); - } + if (result.changed) { + writeFileSync(configPath, result.content); + console.log(`✓ Registered plugin for OpenCode V1 ("plugin") and OpenCode 2 ("plugins") in ${configPath}`); } else { - writeFileSync(configPath, JSON.stringify(config, null, 2)); + console.log("✓ Plugin already registered for OpenCode V1 and OpenCode 2"); } - console.log(`✓ Added plugin to ${configPath}`); + for (const warning of result.warnings) { + console.warn(`⚠ ${warning}`); + } return true; } catch (err) { console.error("✗ Failed to update config:", err); @@ -330,19 +301,15 @@ function addPluginToConfig(configPath: string): boolean { function createNewConfig(): boolean { const configPath = join(OPENCODE_CONFIG_DIR, "opencode.jsonc"); mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true }); - - const config = `{ - "plugin": ["${PLUGIN_NAME}"] -} -`; - - writeFileSync(configPath, config); + + const config = editOpenCodeConfig("{}\n"); + writeFileSync(configPath, config.content); console.log(`✓ Created ${configPath}`); return true; } function createCommands(): boolean { - const files = [ + const files: Array<[string, string]> = [ ["supermemory-index.md", SUPERMEMORY_INDEX_COMMAND], ["supermemory-init.md", SUPERMEMORY_INDEX_COMMAND], ["supermemory-login.md", SUPERMEMORY_LOGIN_COMMAND], @@ -428,7 +395,7 @@ async function install(options: InstallOptions): Promise { const rl = options.tui ? createReadline() : null; // Step 1: Register plugin in config - console.log("Step 1: Register plugin in OpenCode config"); + console.log("Step 1: Register plugin in OpenCode config (OpenCode V1 and OpenCode 2)"); const configPath = findOpencodeConfig(); if (configPath) { @@ -508,7 +475,7 @@ async function install(options: InstallOptions): Promise { console.log("\nOr set your API key manually:"); console.log(' export SUPERMEMORY_API_KEY="sm_..."'); console.log("\n" + "─".repeat(50)); - console.log("\n✓ Setup complete! Restart OpenCode to activate.\n"); + console.log("\n✓ Setup complete! Restart OpenCode (V1 and/or OpenCode 2) to activate.\n"); return 0; } @@ -592,6 +559,28 @@ async function getAccountInfo(apiUrl: string): Promise<{ email?: string; name?: }; } +function describeOpenCodeRegistration(): string[] { + const configPath = findOpencodeConfig(); + if (!configPath) { + return [`OpenCode config: not found (run \`bunx opencode-supermemory@latest install\`)`]; + } + try { + const registration = readOpenCodeRegistration(readFileSync(configPath, "utf-8")); + const v2Permission = registration.recallDenied + ? "recall denied" + : registration.recallAllowed + ? "recall auto-allowed" + : "default permissions"; + return [ + `OpenCode config: ${configPath}`, + `OpenCode V1 plugin entry: ${registration.v1 ? "registered" : `missing (add \"${V1_PLUGIN_ENTRY}\" to \"plugin\")`}`, + `OpenCode 2 plugin entry: ${registration.v2 ? `registered (${v2Permission})` : `missing (add \"${V2_PLUGIN_ENTRY}\" to \"plugins\")`}`, + ]; + } catch (error) { + return [`OpenCode config: ${configPath} (unreadable: ${error instanceof Error ? error.message : String(error)})`]; + } +} + async function status(): Promise { const apiUrl = getApiBaseUrl(); const tags = getTags(process.cwd()); @@ -609,6 +598,7 @@ async function status(): Promise { lines.push(`Project container: ${tags.canonical}`); lines.push(`Personal reads: ${tags.personalReads.join(", ")}`); lines.push(`Project reads: ${tags.projectReads.join(", ")}`); + lines.push(...describeOpenCodeRegistration()); if (!isConfigured()) { lines.push(""); diff --git a/src/config.ts b/src/config.ts index b9f401b..b342f7b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -29,6 +29,8 @@ interface SupermemoryConfig { filterPrompt?: string; keywordPatterns?: string[]; compactionThreshold?: number; + /** OpenCode 2 only: enrich native compaction with project memories and save summaries. */ + compactionEnabled?: boolean; autoRecallEveryPrompt?: boolean; captureEveryNTurns?: number; recallDirective?: string | null; @@ -64,6 +66,7 @@ const DEFAULTS: Required { const { directory } = ctx; const tags = getTags(directory); @@ -286,312 +291,20 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { tool: { supermemory: tool({ - description: - "Manage and query the Supermemory persistent memory system. Use 'search' to find relevant memories, 'add' to store new knowledge, 'profile' to view user profile, 'list' to see recent memories, 'forget' to remove a memory.", + description: SUPERMEMORY_TOOL_DESCRIPTION, args: { - mode: tool.schema - .enum(["add", "search", "profile", "list", "forget", "help"]) - .optional(), + mode: tool.schema.enum(MEMORY_TOOL_MODES).optional(), content: tool.schema.string().optional(), query: tool.schema.string().optional(), - type: tool.schema - .enum([ - "project-config", - "architecture", - "error-solution", - "preference", - "learned-pattern", - "conversation", - ]) - .optional(), - scope: tool.schema.enum(["user", "project"]).optional(), + type: tool.schema.enum(MEMORY_TOOL_TYPES).optional(), + scope: tool.schema.enum(MEMORY_TOOL_SCOPES).optional(), memoryId: tool.schema.string().optional(), limit: tool.schema.number().optional(), }, - async execute(args: { - mode?: string; - content?: string; - query?: string; - type?: MemoryType; - scope?: MemoryScope; - memoryId?: string; - limit?: number; - }) { - if (!isConfigured()) { - return JSON.stringify({ - success: false, - error: - "SUPERMEMORY_API_KEY not set. Set it in your environment to use Supermemory.", - }); - } - - const mode = args.mode || "help"; - - try { - switch (mode) { - case "help": { - return JSON.stringify({ - success: true, - message: "Supermemory Usage Guide", - commands: [ - { - command: "add", - description: "Store a new memory", - args: ["content", "type?", "scope?"], - }, - { - command: "search", - description: "Search memories", - args: ["query", "scope?"], - }, - { - command: "profile", - description: "View user profile", - args: ["query?"], - }, - { - command: "list", - description: "List recent memories", - args: ["scope?", "limit?"], - }, - { - command: "forget", - description: "Remove a memory", - args: ["memoryId", "scope?"], - }, - ], - scopes: { - user: "Personal preferences and knowledge for this project", - project: "Project-specific knowledge (default)", - }, - types: [ - "project-config", - "architecture", - "error-solution", - "preference", - "learned-pattern", - "conversation", - ], - }); - } - - case "add": { - if (!args.content) { - return JSON.stringify({ - success: false, - error: "content parameter is required for add mode", - }); - } - - const sanitizedContent = stripPrivateContent(args.content); - if (isFullyPrivate(args.content)) { - return JSON.stringify({ - success: false, - error: "Cannot store fully private content", - }); - } - - const scope = args.scope || "project"; - const internalScope = - scope === "user" ? "personal" : "project"; - - const result = await supermemoryClient.addMemory( - sanitizedContent, - tags.canonical, - { - type: args.type, - project: tags.projectName, - sm_project_id: tags.projectId, - sm_scope: internalScope, - sm_capture_mode: "tool", - }, - { entityContext: AGENT_ENTITY_CONTEXT } - ); - - if (!result.success) { - return JSON.stringify({ - success: false, - error: result.error || "Failed to add memory", - }); - } - - activity.saved(); - - return JSON.stringify({ - success: true, - message: `Memory added to ${scope} scope`, - id: result.id, - scope, - type: args.type, - }); - } - - case "search": { - if (!args.query) { - return JSON.stringify({ - success: false, - error: "query parameter is required for search mode", - }); - } - - const scope = args.scope; - - if (scope === "user") { - const result = await supermemoryClient.searchMemoriesScoped( - args.query, - tags.canonical, - tags.personalReads, - "personal", - ); - if (!result.success) { - return JSON.stringify({ - success: false, - error: result.error || "Failed to search memories", - }); - } - return formatSearchResults(args.query, scope, result, args.limit); - } - - if (scope === "project") { - const result = await supermemoryClient.searchMemoriesScoped( - args.query, - tags.canonical, - tags.projectReads, - "project", - ); - if (!result.success) { - return JSON.stringify({ - success: false, - error: result.error || "Failed to search memories", - }); - } - return formatSearchResults(args.query, scope, result, args.limit); - } - - const result = await supermemoryClient.searchMemoriesMany( - args.query, - tags.allReads, - ); - if (!result.success) { - return JSON.stringify({ - success: false, - error: result.error || "Failed to search memories", - }); - } - return formatSearchResults( - args.query, - undefined, - result, - args.limit, - ); - } - - case "profile": { - const result = await supermemoryClient.getProfileScoped( - tags.canonical, - tags.personalReads, - "personal", - args.query, - ); - - if (!result.success) { - return JSON.stringify({ - success: false, - error: result.error || "Failed to fetch profile", - }); - } - - return JSON.stringify({ - success: true, - profile: { - static: result.profile?.static || [], - dynamic: result.profile?.dynamic || [], - }, - }); - } - - case "list": { - const scope = args.scope || "project"; - const limit = args.limit || 20; - const internalScope = - scope === "user" ? "personal" : "project"; - const readTags = - scope === "user" ? tags.personalReads : tags.projectReads; - - const result = await supermemoryClient.listMemoriesScoped( - tags.canonical, - readTags, - internalScope, - limit, - ); - - if (!result.success) { - return JSON.stringify({ - success: false, - error: result.error || "Failed to list memories", - }); - } - - const memories = result.memories || []; - return JSON.stringify({ - success: true, - scope, - count: memories.length, - memories: memories.map((m) => ({ - id: m.id, - content: m.summary, - createdAt: m.createdAt, - metadata: m.metadata, - })), - }); - } - - case "forget": { - if (!args.memoryId) { - return JSON.stringify({ - success: false, - error: "memoryId parameter is required for forget mode", - }); - } - - const scope = args.scope || "project"; - const readTags = - scope === "user" - ? tags.personalReads - : scope === "project" - ? tags.projectReads - : tags.allReads; - - const result = await supermemoryClient.deleteMemory( - args.memoryId, - [tags.canonical, ...readTags], - ); - - if (!result.success) { - return JSON.stringify({ - success: false, - error: result.error || "Failed to delete memory", - }); - } - - return JSON.stringify({ - success: true, - message: `Memory ${args.memoryId} removed from ${scope} scope`, - }); - } - - default: - return JSON.stringify({ - success: false, - error: `Unknown mode: ${mode}`, - }); - } - } catch (error) { - return JSON.stringify({ - success: false, - error: error instanceof Error ? error.message : String(error), - }); - } + async execute(args: SupermemoryToolArgs) { + return executeSupermemoryTool(args, tags, { + onSaved: () => activity.saved(), + }); }, }), }, @@ -666,50 +379,3 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { }, }; }; - -function formatSearchResults( - query: string, - scope: string | undefined, - results: { - results?: Array<{ - id?: string; - memory?: string; - chunk?: string; - content?: string; - text?: string; - context?: unknown; - similarity?: number; - score?: number; - title?: string; - filepath?: string; - metadata?: Record | null; - }>; - }, - limit?: number -): string { - const memoryResults = (results.results || []) - .map((result) => normalizeRecallResult(result)) - .filter((hit): hit is NonNullable => hit !== null) - .slice(0, limit ?? 10); - return JSON.stringify({ - success: true, - query, - scope, - count: memoryResults.length, - results: memoryResults.map((hit) => { - const r = hit.result; - const result = { - content: formatRecallHit(hit), - ...(hit.similarity === undefined - ? {} - : { similarity: Math.round(hit.similarity * 100) }), - ...(hit.title ? { title: hit.title } : {}), - ...(hit.filepath ? { filepath: hit.filepath } : {}), - }; - - return r.memory === undefined - ? { ...result, forgettable: false } - : { id: r.id, ...result, forgettable: true }; - }), - }); -} diff --git a/src/rpc.ts b/src/rpc.ts new file mode 100644 index 0000000..5ee0eab --- /dev/null +++ b/src/rpc.ts @@ -0,0 +1,59 @@ +/** + * OpenCode 2 RPC contract shared by the server plugin (`opencode-supermemory/server`) + * and the TUI companion (`opencode-supermemory/tui`). The server emits activity + * notices here and the TUI renders them as toasts, so notices never enter model + * context. Importable as `opencode-supermemory/rpc` without loading either side. + */ +import type { Rpc } from "@opencode/plugin/rpc"; + +export const SUPERMEMORY_RPC_ID = "supermemory"; + +/** Wire type of the activity event, as seen on the OpenCode event stream. */ +export const SUPERMEMORY_ACTIVITY_EVENT = `rpc.${SUPERMEMORY_RPC_ID}.activity`; + +export type SupermemoryActivityVariant = "info" | "success" | "warning" | "error"; + +export interface SupermemoryActivityEvent { + kind: string; + title: string; + message: string; + variant: SupermemoryActivityVariant; + duration: number; +} + +export const SUPERMEMORY_RPC = { + id: SUPERMEMORY_RPC_ID, + methods: {}, + events: { + activity: { + schema: { + type: "object", + properties: { + kind: { type: "string" }, + title: { type: "string" }, + message: { type: "string" }, + variant: { + type: "string", + enum: ["info", "success", "warning", "error"], + }, + duration: { type: "number" }, + }, + required: ["kind", "title", "message", "variant", "duration"], + additionalProperties: false, + }, + }, + }, +} as const satisfies Rpc.PortableDefinition; + +export function isSupermemoryActivityEvent( + value: unknown, +): value is SupermemoryActivityEvent { + if (!value || typeof value !== "object") return false; + const data = value as Record; + return ( + typeof data.message === "string" && + typeof data.title === "string" && + typeof data.variant === "string" && + typeof data.duration === "number" + ); +} diff --git a/src/server.ts b/src/server.ts new file mode 100644 index 0000000..45e74fd --- /dev/null +++ b/src/server.ts @@ -0,0 +1,15 @@ +/** + * OpenCode 2 server plugin entry, resolved as `opencode-supermemory/server`. + * The root export stays the OpenCode V1 plugin so both generations can load + * the same package. + */ +import type { Plugin } from "@opencode/plugin"; + +import { setupV2 } from "./v2/runtime.js"; + +const plugin: Plugin.Plugin = { + id: "supermemory", + setup: (context) => setupV2(context), +}; + +export default plugin; diff --git a/src/services/activity.ts b/src/services/activity.ts index df5bb00..9d5f3ea 100644 --- a/src/services/activity.ts +++ b/src/services/activity.ts @@ -3,12 +3,22 @@ import type { PluginInput } from "@opencode-ai/plugin"; import { log } from "./logger.js"; import type { UpdateInfo } from "./version-check.js"; -type ToastVariant = "info" | "success" | "warning" | "error"; +export type ActivityVariant = "info" | "success" | "warning" | "error"; -interface ToastClient { - tui: { - showToast: PluginInput["client"]["tui"]["showToast"]; - }; +export type ActivityKind = + | "recalling" + | "recalled" + | "recall-unavailable" + | "saved" + | "update-available"; + +/** A user-facing notice about Supermemory activity, independent of the UI. */ +export interface MemoryActivityNotice { + kind: ActivityKind; + title: string; + message: string; + variant: ActivityVariant; + duration: number; } export interface MemoryActivityReporter { @@ -19,58 +29,104 @@ export interface MemoryActivityReporter { updateAvailable(info: UpdateInfo): void; } -export function createMemoryActivityReporter( - client: ToastClient, +export const ACTIVITY_TITLE = "Supermemory"; +const ACTIVITY_PREFIX = "◪ supermemory · "; + +function notice( + kind: ActivityKind, + message: string, + variant: ActivityVariant, + duration: number, +): MemoryActivityNotice { + return { + kind, + title: ACTIVITY_TITLE, + message: `${ACTIVITY_PREFIX}${message}`, + variant, + duration, + }; +} + +/** + * Builds reporters on top of any notice sink, so OpenCode V1 (TUI toasts) and + * OpenCode 2 (plugin RPC events rendered by the TUI plugin) show the same text. + */ +export function createMemoryActivityReporterFromSink( + show: (notice: MemoryActivityNotice) => void, ): MemoryActivityReporter { - const show = ( - message: string, - variant: ToastVariant, - duration: number, - ) => { - void client.tui - .showToast({ - body: { - title: "Supermemory", - message: `◪ supermemory · ${message}`, - variant, - duration, - }, - }) - .catch((error) => { - log("[activity] unable to show TUI notification", { - error: String(error), - }); - }); + const emit = (item: MemoryActivityNotice) => { + try { + show(item); + } catch (error) { + log("[activity] unable to show notification", { error: String(error) }); + } }; return { recalling(query) { const suffix = query?.trim() ? `: ${query.trim().slice(0, 100)}` : ""; - show(`recalling${suffix}`, "info", 2_000); + emit(notice("recalling", `recalling${suffix}`, "info", 2_000)); }, recalled(count, tokens) { - show( - `recalled ${count} ${count === 1 ? "memory" : "memories"} (${tokens} tok)`, - "success", - 3_000, + emit( + notice( + "recalled", + `recalled ${count} ${count === 1 ? "memory" : "memories"} (${tokens} tok)`, + "success", + 3_000, + ), ); }, recallUnavailable() { - show( - "recall unavailable; continuing without recalled context", - "warning", - 3_000, + emit( + notice( + "recall-unavailable", + "recall unavailable; continuing without recalled context", + "warning", + 3_000, + ), ); }, saved() { - show("saved this turn", "success", 2_000); + emit(notice("saved", "saved this turn", "success", 2_000)); }, updateAvailable(info) { - show( - `update available: v${info.currentVersion} → v${info.latestVersion} · ${info.updateCommand}`, - "info", - 8_000, + emit( + notice( + "update-available", + `update available: v${info.currentVersion} → v${info.latestVersion} · ${info.updateCommand}`, + "info", + 8_000, + ), ); }, }; } + +interface ToastClient { + tui: { + showToast: PluginInput["client"]["tui"]["showToast"]; + }; +} + +/** OpenCode V1 reporter: native TUI toasts via the SDK client. */ +export function createMemoryActivityReporter( + client: ToastClient, +): MemoryActivityReporter { + return createMemoryActivityReporterFromSink((item) => { + void client.tui + .showToast({ + body: { + title: item.title, + message: item.message, + variant: item.variant, + duration: item.duration, + }, + }) + .catch((error) => { + log("[activity] unable to show TUI notification", { + error: String(error), + }); + }); + }); +} diff --git a/src/services/compaction-prompt.ts b/src/services/compaction-prompt.ts new file mode 100644 index 0000000..56f51be --- /dev/null +++ b/src/services/compaction-prompt.ts @@ -0,0 +1,71 @@ +export const COMPACTION_CONTEXT_MARKER = "[SUPERMEMORY COMPACTION CONTEXT]"; +const MAX_COMPACTION_MEMORY_CHARS = 12_000; +const MAX_SINGLE_MEMORY_CHARS = 2_000; + +/** + * Bounds the project memories injected into a compaction prompt so a large + * memory store cannot crowd out the transcript being summarized. + */ +export function fitProjectMemories(memories: string[]): string[] { + const result: string[] = []; + const seen = new Set(); + let remaining = MAX_COMPACTION_MEMORY_CHARS; + + for (const rawMemory of memories) { + const normalized = rawMemory.trim(); + if (!normalized || seen.has(normalized) || remaining <= 0) continue; + seen.add(normalized); + + const memory = normalized.slice( + 0, + Math.min(MAX_SINGLE_MEMORY_CHARS, remaining), + ); + result.push(memory); + remaining -= memory.length; + } + + return result; +} + +export function createCompactionPrompt(projectMemories: string[]): string { + const memoriesSection = + projectMemories.length > 0 + ? ` +## Project Knowledge (from Supermemory) +The following project-specific knowledge should be preserved and referenced in the summary: +${projectMemories.map((memory) => `- ${memory}`).join("\n")} +` + : ""; + + return `${COMPACTION_CONTEXT_MARKER} + +When summarizing this session, you MUST include the following sections in your summary: + +## 1. User Requests (As-Is) +- List all original user requests exactly as they were stated +- Preserve the user's exact wording and intent + +## 2. Final Goal +- What the user ultimately wanted to achieve +- The end result or deliverable expected + +## 3. Work Completed +- What has been done so far +- Files created/modified +- Features implemented +- Problems solved + +## 4. Remaining Tasks +- What still needs to be done +- Pending items from the original request +- Follow-up tasks identified during the work + +## 5. MUST NOT Do (Critical Constraints) +- Things that were explicitly forbidden +- Approaches that failed and should not be retried +- User's explicit restrictions or preferences +- Anti-patterns identified during the session +${memoriesSection} +This context is critical for maintaining continuity after compaction. +`; +} diff --git a/src/services/compaction.ts b/src/services/compaction.ts index f925892..e44353d 100644 --- a/src/services/compaction.ts +++ b/src/services/compaction.ts @@ -2,6 +2,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from import { join } from "node:path"; import { homedir } from "node:os"; import { AGENT_ENTITY_CONTEXT } from "./entity-context.js"; +import { createCompactionPrompt } from "./compaction-prompt.js"; import { supermemoryClient } from "./client.js"; import { log } from "./logger.js"; import { CONFIG } from "../config.js"; @@ -57,48 +58,6 @@ export interface CompactionOptions { getModelLimit?: (providerID: string, modelID: string) => number | undefined; } -function createCompactionPrompt(projectMemories: string[]): string { - const memoriesSection = projectMemories.length > 0 - ? ` -## Project Knowledge (from Supermemory) -The following project-specific knowledge should be preserved and referenced in the summary: -${projectMemories.map(m => `- ${m}`).join('\n')} -` - : ''; - - return `[COMPACTION CONTEXT INJECTION] - -When summarizing this session, you MUST include the following sections in your summary: - -## 1. User Requests (As-Is) -- List all original user requests exactly as they were stated -- Preserve the user's exact wording and intent - -## 2. Final Goal -- What the user ultimately wanted to achieve -- The end result or deliverable expected - -## 3. Work Completed -- What has been done so far -- Files created/modified -- Features implemented -- Problems solved - -## 4. Remaining Tasks -- What still needs to be done -- Pending items from the original request -- Follow-up tasks identified during the work - -## 5. MUST NOT Do (Critical Constraints) -- Things that were explicitly forbidden -- Approaches that failed and should not be retried -- User's explicit restrictions or preferences -- Anti-patterns identified during the session -${memoriesSection} -This context is critical for maintaining continuity after compaction. -`; -} - function getMessageDir(sessionID: string): string | null { if (!existsSync(MESSAGE_STORAGE)) return null; diff --git a/src/services/memory-tool.test.ts b/src/services/memory-tool.test.ts new file mode 100644 index 0000000..5b9224e --- /dev/null +++ b/src/services/memory-tool.test.ts @@ -0,0 +1,147 @@ +import { describe, expect, test } from "bun:test"; + +import { + executeSupermemoryTool, + type MemoryToolClient, +} from "./memory-tool.js"; +import type { ResolvedTags } from "./tags.js"; + +const tags: ResolvedTags = { + canonical: "repo_test__0123456789abcdef", + user: "repo_test__0123456789abcdef", + project: "repo_test__0123456789abcdef", + projectId: "0123456789abcdef", + projectName: "test", + personalReads: ["legacy_user"], + projectReads: ["legacy_project"], + allReads: ["legacy_user", "legacy_project"], +}; + +function client(overrides: Partial): MemoryToolClient { + const unsupported = async () => { + throw new Error("not used in this test"); + }; + return { + addMemory: unsupported, + searchMemoriesScoped: unsupported, + searchMemoriesMany: unsupported, + getProfileScoped: unsupported, + listMemoriesScoped: unsupported, + deleteMemory: unsupported, + ...overrides, + } as MemoryToolClient; +} + +describe("shared supermemory tool", () => { + test("refuses to run without an API key", async () => { + const result = JSON.parse( + await executeSupermemoryTool({ mode: "search", query: "x" }, tags, { + configured: false, + }), + ); + expect(result.success).toBe(false); + expect(result.error).toContain("SUPERMEMORY_API_KEY"); + }); + + test("add redacts private content, tags the scope, and reports saves", async () => { + const calls: unknown[] = []; + let saved = 0; + const result = JSON.parse( + await executeSupermemoryTool( + { + mode: "add", + content: "Use bun token abc for builds", + scope: "user", + type: "preference", + }, + tags, + { + configured: true, + onSaved: () => { + saved += 1; + }, + memoryClient: client({ + addMemory: async (content, containerTag, metadata) => { + calls.push({ content, containerTag, metadata }); + return { success: true, id: "mem_1" }; + }, + } as Partial), + }, + ), + ); + + expect(result).toMatchObject({ success: true, id: "mem_1", scope: "user" }); + expect(saved).toBe(1); + expect(calls[0]).toMatchObject({ + content: "Use bun [REDACTED] for builds", + containerTag: tags.canonical, + metadata: { sm_scope: "personal", sm_capture_mode: "tool", type: "preference" }, + }); + }); + + test("search normalizes result shapes and marks memories forgettable", async () => { + const result = JSON.parse( + await executeSupermemoryTool({ mode: "search", query: "build" }, tags, { + configured: true, + memoryClient: client({ + searchMemoriesMany: async () => ({ + success: true, + results: [ + { id: "m1", memory: "Build with bun", similarity: 0.91 }, + { + content: "Deploy notes", + title: "Release", + filepath: "docs/release.md", + score: 0.7, + }, + ], + }), + } as Partial), + }), + ); + + expect(result.count).toBe(2); + expect(result.results[0]).toEqual({ + id: "m1", + content: "Build with bun", + similarity: 91, + forgettable: true, + }); + expect(result.results[1]).toEqual({ + content: "Release: Deploy notes (docs/release.md)", + similarity: 70, + title: "Release", + filepath: "docs/release.md", + forgettable: false, + }); + }); + + test("forget requires a memory id and searches every read container", async () => { + const missing = JSON.parse( + await executeSupermemoryTool({ mode: "forget" }, tags, { + configured: true, + memoryClient: client({}), + }), + ); + expect(missing.success).toBe(false); + + let containers: string[] = []; + const result = JSON.parse( + await executeSupermemoryTool( + { mode: "forget", memoryId: "m1", scope: "user" }, + tags, + { + configured: true, + memoryClient: client({ + deleteMemory: async (_id, containerTags) => { + containers = containerTags ?? []; + return { success: true }; + }, + } as Partial), + }, + ), + ); + expect(result.success).toBe(true); + expect(containers).toEqual([tags.canonical, "legacy_user"]); + }); +}); diff --git a/src/services/memory-tool.ts b/src/services/memory-tool.ts new file mode 100644 index 0000000..53793f9 --- /dev/null +++ b/src/services/memory-tool.ts @@ -0,0 +1,382 @@ +import { isConfigured } from "../config.js"; +import type { MemoryScope, MemoryType } from "../types/index.js"; +import { supermemoryClient, type SupermemoryClient } from "./client.js"; +import { AGENT_ENTITY_CONTEXT } from "./entity-context.js"; +import { isFullyPrivate, stripPrivateContent } from "./privacy.js"; +import { formatRecallHit, normalizeRecallResult } from "./recall-results.js"; +import type { ResolvedTags } from "./tags.js"; + +export const SUPERMEMORY_TOOL_DESCRIPTION = + "Manage and query the Supermemory persistent memory system. Use 'search' to find relevant memories, 'add' to store new knowledge, 'profile' to view user profile, 'list' to see recent memories, 'forget' to remove a memory."; + +export const SUPERMEMORY_RECALL_TOOL_DESCRIPTION = + "Search saved Supermemory context for this repository and user. This least-privilege helper only accepts search operations."; + +export const MEMORY_TOOL_MODES = [ + "add", + "search", + "profile", + "list", + "forget", + "help", +] as const; + +export const MEMORY_TOOL_TYPES = [ + "project-config", + "architecture", + "error-solution", + "preference", + "learned-pattern", + "conversation", +] as const; + +export const MEMORY_TOOL_SCOPES = ["user", "project"] as const; + +export interface SupermemoryToolArgs { + mode?: string; + content?: string; + query?: string; + type?: MemoryType; + scope?: MemoryScope; + memoryId?: string; + limit?: number; +} + +export type MemoryToolClient = Pick< + SupermemoryClient, + | "addMemory" + | "searchMemoriesScoped" + | "searchMemoriesMany" + | "getProfileScoped" + | "listMemoriesScoped" + | "deleteMemory" +>; + +export interface MemoryToolOptions { + memoryClient?: MemoryToolClient; + configured?: boolean; + /** Called after a memory is stored through the tool. */ + onSaved?: () => void; +} + +/** + * Shared implementation of the `supermemory` tool used by both the OpenCode V1 + * plugin and the OpenCode 2 server plugin, so both generations behave alike. + */ +export async function executeSupermemoryTool( + args: SupermemoryToolArgs, + tags: ResolvedTags, + options: MemoryToolOptions = {}, +): Promise { + const memoryClient = options.memoryClient ?? supermemoryClient; + const configured = options.configured ?? isConfigured(); + + if (!configured) { + return JSON.stringify({ + success: false, + error: + "SUPERMEMORY_API_KEY not set. Set it in your environment to use Supermemory.", + }); + } + + const mode = args.mode || "help"; + + try { + switch (mode) { + case "help": { + return JSON.stringify({ + success: true, + message: "Supermemory Usage Guide", + commands: [ + { + command: "add", + description: "Store a new memory", + args: ["content", "type?", "scope?"], + }, + { + command: "search", + description: "Search memories", + args: ["query", "scope?"], + }, + { + command: "profile", + description: "View user profile", + args: ["query?"], + }, + { + command: "list", + description: "List recent memories", + args: ["scope?", "limit?"], + }, + { + command: "forget", + description: "Remove a memory", + args: ["memoryId", "scope?"], + }, + ], + scopes: { + user: "Personal preferences and knowledge for this project", + project: "Project-specific knowledge (default)", + }, + types: [...MEMORY_TOOL_TYPES], + }); + } + + case "add": { + if (!args.content) { + return JSON.stringify({ + success: false, + error: "content parameter is required for add mode", + }); + } + + const sanitizedContent = stripPrivateContent(args.content); + if (isFullyPrivate(args.content)) { + return JSON.stringify({ + success: false, + error: "Cannot store fully private content", + }); + } + + const scope = args.scope || "project"; + const internalScope = scope === "user" ? "personal" : "project"; + + const result = await memoryClient.addMemory( + sanitizedContent, + tags.canonical, + { + type: args.type, + project: tags.projectName, + sm_project_id: tags.projectId, + sm_scope: internalScope, + sm_capture_mode: "tool", + }, + { entityContext: AGENT_ENTITY_CONTEXT }, + ); + + if (!result.success) { + return JSON.stringify({ + success: false, + error: result.error || "Failed to add memory", + }); + } + + options.onSaved?.(); + + return JSON.stringify({ + success: true, + message: `Memory added to ${scope} scope`, + id: result.id, + scope, + type: args.type, + }); + } + + case "search": { + if (!args.query) { + return JSON.stringify({ + success: false, + error: "query parameter is required for search mode", + }); + } + + const scope = args.scope; + + if (scope === "user") { + const result = await memoryClient.searchMemoriesScoped( + args.query, + tags.canonical, + tags.personalReads, + "personal", + ); + if (!result.success) { + return JSON.stringify({ + success: false, + error: result.error || "Failed to search memories", + }); + } + return formatSearchResults(args.query, scope, result, args.limit); + } + + if (scope === "project") { + const result = await memoryClient.searchMemoriesScoped( + args.query, + tags.canonical, + tags.projectReads, + "project", + ); + if (!result.success) { + return JSON.stringify({ + success: false, + error: result.error || "Failed to search memories", + }); + } + return formatSearchResults(args.query, scope, result, args.limit); + } + + const result = await memoryClient.searchMemoriesMany( + args.query, + tags.allReads, + ); + if (!result.success) { + return JSON.stringify({ + success: false, + error: result.error || "Failed to search memories", + }); + } + return formatSearchResults(args.query, undefined, result, args.limit); + } + + case "profile": { + const result = await memoryClient.getProfileScoped( + tags.canonical, + tags.personalReads, + "personal", + args.query, + ); + + if (!result.success) { + return JSON.stringify({ + success: false, + error: result.error || "Failed to fetch profile", + }); + } + + return JSON.stringify({ + success: true, + profile: { + static: result.profile?.static || [], + dynamic: result.profile?.dynamic || [], + }, + }); + } + + case "list": { + const scope = args.scope || "project"; + const limit = args.limit || 20; + const internalScope = scope === "user" ? "personal" : "project"; + const readTags = + scope === "user" ? tags.personalReads : tags.projectReads; + + const result = await memoryClient.listMemoriesScoped( + tags.canonical, + readTags, + internalScope, + limit, + ); + + if (!result.success) { + return JSON.stringify({ + success: false, + error: result.error || "Failed to list memories", + }); + } + + const memories = result.memories || []; + return JSON.stringify({ + success: true, + scope, + count: memories.length, + memories: memories.map((memory) => ({ + id: memory.id, + content: memory.summary, + createdAt: memory.createdAt, + metadata: memory.metadata, + })), + }); + } + + case "forget": { + if (!args.memoryId) { + return JSON.stringify({ + success: false, + error: "memoryId parameter is required for forget mode", + }); + } + + const scope = args.scope || "project"; + const readTags = + scope === "user" + ? tags.personalReads + : scope === "project" + ? tags.projectReads + : tags.allReads; + + const result = await memoryClient.deleteMemory(args.memoryId, [ + tags.canonical, + ...readTags, + ]); + + if (!result.success) { + return JSON.stringify({ + success: false, + error: result.error || "Failed to delete memory", + }); + } + + return JSON.stringify({ + success: true, + message: `Memory ${args.memoryId} removed from ${scope} scope`, + }); + } + + default: + return JSON.stringify({ + success: false, + error: `Unknown mode: ${mode}`, + }); + } + } catch (error) { + return JSON.stringify({ + success: false, + error: error instanceof Error ? error.message : String(error), + }); + } +} + +export function formatSearchResults( + query: string, + scope: string | undefined, + results: { + results?: Array<{ + id?: string; + memory?: string; + chunk?: string; + content?: string; + text?: string; + context?: unknown; + similarity?: number; + score?: number; + title?: string; + filepath?: string; + metadata?: Record | null; + }>; + }, + limit?: number, +): string { + const memoryResults = (results.results || []) + .map((result) => normalizeRecallResult(result)) + .filter((hit): hit is NonNullable => hit !== null) + .slice(0, limit ?? 10); + return JSON.stringify({ + success: true, + query, + scope, + count: memoryResults.length, + results: memoryResults.map((hit) => { + const r = hit.result; + const result = { + content: formatRecallHit(hit), + ...(hit.similarity === undefined + ? {} + : { similarity: Math.round(hit.similarity * 100) }), + ...(hit.title ? { title: hit.title } : {}), + ...(hit.filepath ? { filepath: hit.filepath } : {}), + }; + + return r.memory === undefined + ? { ...result, forgettable: false } + : { id: r.id, ...result, forgettable: true }; + }), + }); +} diff --git a/src/services/opencode-config.test.ts b/src/services/opencode-config.test.ts new file mode 100644 index 0000000..1590197 --- /dev/null +++ b/src/services/opencode-config.test.ts @@ -0,0 +1,76 @@ +import { describe, expect, test } from "bun:test"; + +import { + editOpenCodeConfig, + readOpenCodeRegistration, + RECALL_PERMISSION, + V1_PLUGIN_ENTRY, + V2_PLUGIN_ENTRY, +} from "./opencode-config.js"; + +describe("OpenCode config editor", () => { + test("registers both plugin generations in an empty config", () => { + const result = editOpenCodeConfig(""); + const config = JSON.parse(result.content); + + expect(result.changed).toBe(true); + expect(config.plugin).toEqual([V1_PLUGIN_ENTRY]); + expect(config.plugins).toEqual([V2_PLUGIN_ENTRY]); + expect(config.permissions).toEqual([RECALL_PERMISSION]); + expect(result.warnings).toEqual([]); + }); + + test("preserves comments and existing local checkouts, and is idempotent", () => { + const original = `{ + // OpenCode V1 loads a local checkout while developing + "plugin": ["file:///Users/me/opencode-supermemory"], + "$schema": "https://opencode.ai/config.json", +} +`; + const first = editOpenCodeConfig(original); + expect(first.changed).toBe(true); + expect(first.content).toContain("// OpenCode V1 loads a local checkout"); + expect(first.content).toContain('"file:///Users/me/opencode-supermemory"'); + expect(first.content).not.toContain(V1_PLUGIN_ENTRY); + const config = JSON.parse(first.content.replace(/^\s*\/\/.*$/gm, "").replace(/,(\s*[}\]])/g, "$1")); + expect(config.plugins).toEqual([V2_PLUGIN_ENTRY]); + expect(config.permissions).toEqual([RECALL_PERMISSION]); + + const second = editOpenCodeConfig(first.content); + expect(second.changed).toBe(false); + expect(second.content).toBe(first.content); + + const registration = readOpenCodeRegistration(first.content); + expect(registration).toEqual({ + v1: true, + v2: true, + recallAllowed: true, + recallDenied: false, + }); + }); + + test("recognises object entries and pinned versions as registered", () => { + const content = JSON.stringify({ + plugin: ["opencode-supermemory@2.0.13"], + plugins: [{ package: "opencode-supermemory@latest", options: {} }], + permissions: [RECALL_PERMISSION], + }); + expect(editOpenCodeConfig(content).changed).toBe(false); + }); + + test("keeps an explicit recall deny and warns instead of overriding it", () => { + const deny = { ...RECALL_PERMISSION, effect: "deny" }; + const result = editOpenCodeConfig(JSON.stringify({ permissions: [deny] })); + const config = JSON.parse(result.content); + + expect(config.permissions).toEqual([deny]); + expect(result.warnings).toHaveLength(1); + expect(readOpenCodeRegistration(result.content).recallDenied).toBe(true); + }); + + test("rejects configs whose arrays are not arrays", () => { + expect(() => editOpenCodeConfig('{"plugins": "nope"}')).toThrow( + /must be an array/, + ); + }); +}); diff --git a/src/services/opencode-config.ts b/src/services/opencode-config.ts new file mode 100644 index 0000000..056dadf --- /dev/null +++ b/src/services/opencode-config.ts @@ -0,0 +1,189 @@ +import { + applyEdits, + modify, + parse, + type FormattingOptions, + type ParseError, +} from "jsonc-parser/lib/esm/main.js"; + +/** OpenCode V1 reads the singular `plugin` array. */ +export const V1_PLUGIN_ENTRY = "opencode-supermemory@latest"; +/** + * OpenCode 2 reads the plural `plugins` array and resolves the package's + * `./server` export (falling back to the root), so the bare package name is + * enough. Leaving the version unpinned lets `opencode plugin update` work. + */ +export const V2_PLUGIN_ENTRY = "opencode-supermemory"; + +export const PACKAGE_NAME = "opencode-supermemory"; + +export { RECALL_PERMISSION } from "./opencode-permissions.js"; +import { RECALL_PERMISSION } from "./opencode-permissions.js"; + +export interface OpenCodeConfigEditResult { + content: string; + changed: boolean; + warnings: string[]; +} + +export interface OpenCodeRegistration { + v1: boolean; + v2: boolean; + recallAllowed: boolean; + recallDenied: boolean; +} + +type JsonObject = Record; + +function isObject(value: unknown): value is JsonObject { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +export function parseOpenCodeConfig(content: string): JsonObject { + const errors: ParseError[] = []; + const value = parse(content, errors, { + allowTrailingComma: true, + disallowComments: false, + }); + + if (errors.length > 0) { + const first = errors[0]!; + throw new Error(`Invalid OpenCode JSONC config at offset ${first.offset}`); + } + + if (!isObject(value)) { + throw new Error("OpenCode config must contain a JSON object"); + } + + return value; +} + +function getFormattingOptions(content: string): FormattingOptions { + const eol = content.includes("\r\n") ? "\r\n" : "\n"; + const indent = content.match(/\r?\n([ \t]+)["}]/)?.[1]; + const usesTabs = indent?.includes("\t") ?? false; + + return { + eol, + insertSpaces: !usesTabs, + tabSize: usesTabs ? 1 : Math.max(2, indent?.length ?? 2), + }; +} + +function applyModification( + content: string, + path: Array, + value: unknown, +): string { + return applyEdits( + content, + modify(content, path, value, { + formattingOptions: getFormattingOptions(content), + }), + ); +} + +function getPluginPackage(value: unknown): string | undefined { + if (typeof value === "string") return value; + if (isObject(value) && typeof value.package === "string") { + return value.package; + } + if (Array.isArray(value) && typeof value[0] === "string") return value[0]; + return undefined; +} + +/** + * Any entry that refers to this package counts as registered, including local + * `file:` checkouts and pinned versions, so the installer never adds a second + * copy next to a development install. + */ +export function isSupermemoryPluginEntry(value: unknown): boolean { + const packageName = getPluginPackage(value); + return packageName !== undefined && packageName.includes(PACKAGE_NAME); +} + +function addArrayEntry( + content: string, + property: string, + value: unknown, + alreadyPresent: (entry: unknown) => boolean, +): string { + const config = parseOpenCodeConfig(content); + const current = config[property]; + + if (current === undefined) { + return applyModification(content, [property], [value]); + } + + if (!Array.isArray(current)) { + throw new Error(`OpenCode config property "${property}" must be an array`); + } + + if (current.some(alreadyPresent)) return content; + return applyModification(content, [property, -1], value); +} + +function isRecallPermission(value: unknown, effect: "allow" | "deny"): boolean { + return ( + isObject(value) && + value.action === RECALL_PERMISSION.action && + value.resource === RECALL_PERMISSION.resource && + value.effect === effect + ); +} + +export function readOpenCodeRegistration(content: string): OpenCodeRegistration { + const config = parseOpenCodeConfig(content); + const plugin = Array.isArray(config.plugin) ? config.plugin : []; + const plugins = Array.isArray(config.plugins) ? config.plugins : []; + const permissions = Array.isArray(config.permissions) ? config.permissions : []; + return { + v1: plugin.some(isSupermemoryPluginEntry), + v2: plugins.some(isSupermemoryPluginEntry), + recallAllowed: permissions.some((entry) => isRecallPermission(entry, "allow")), + recallDenied: permissions.some((entry) => isRecallPermission(entry, "deny")), + }; +} + +/** + * Adds the OpenCode V1 and OpenCode 2 plugin entries without rewriting + * unrelated JSONC. Existing entries (including local checkouts) are kept, and + * an explicit recall deny is respected. + */ +export function editOpenCodeConfig(rawContent: string): OpenCodeConfigEditResult { + const original = rawContent; + let content = rawContent.trim() === "" ? "{}\n" : rawContent; + const warnings: string[] = []; + + parseOpenCodeConfig(content); + content = addArrayEntry(content, "plugin", V1_PLUGIN_ENTRY, isSupermemoryPluginEntry); + content = addArrayEntry(content, "plugins", V2_PLUGIN_ENTRY, isSupermemoryPluginEntry); + + const config = parseOpenCodeConfig(content); + const permissions = config.permissions; + if (permissions !== undefined && !Array.isArray(permissions)) { + throw new Error('OpenCode config property "permissions" must be an array'); + } + + const permissionEntries = permissions ?? []; + if (permissionEntries.some((entry) => isRecallPermission(entry, "deny"))) { + warnings.push( + 'OpenCode 2 permission "supermemory_recall" is explicitly denied; preserving the deny instead of adding an allow.', + ); + } else if ( + !permissionEntries.some((entry) => isRecallPermission(entry, "allow")) + ) { + content = addArrayEntry( + content, + "permissions", + RECALL_PERMISSION, + (entry) => isRecallPermission(entry, "allow"), + ); + } + + return { + content, + changed: content !== original, + warnings, + }; +} diff --git a/src/services/opencode-permissions.ts b/src/services/opencode-permissions.ts new file mode 100644 index 0000000..700aec4 --- /dev/null +++ b/src/services/opencode-permissions.ts @@ -0,0 +1,10 @@ +/** + * OpenCode 2 permission rule that lets the read-only `supermemory_recall` tool + * run without prompting. Kept dependency-free so the server plugin bundle does + * not pull in the JSONC editor used by the installer. + */ +export const RECALL_PERMISSION = { + action: "supermemory_recall", + resource: "*", + effect: "allow", +} as const; diff --git a/src/tui.ts b/src/tui.ts new file mode 100644 index 0000000..3f079d9 --- /dev/null +++ b/src/tui.ts @@ -0,0 +1,34 @@ +/** + * OpenCode 2 TUI companion. OpenCode resolves `opencode-supermemory/tui` + * automatically next to the server entry and runs it inside the terminal UI. + * It only renders activity notices emitted by the server plugin as toasts. + */ +import type { Plugin as TuiPlugin } from "@opencode/plugin/tui"; + +type Context = TuiPlugin.Context; +type Definition = TuiPlugin.Definition; + +import { + isSupermemoryActivityEvent, + SUPERMEMORY_ACTIVITY_EVENT, +} from "./rpc.js"; + +const plugin: Definition = { + id: "supermemory.tui", + setup(context: Context) { + const stop = context.data.listen(({ details }) => { + if (details.type !== SUPERMEMORY_ACTIVITY_EVENT) return; + const data = (details as { data?: unknown }).data; + if (!isSupermemoryActivityEvent(data)) return; + context.ui.toast.show({ + title: data.title, + message: data.message, + variant: data.variant, + duration: data.duration, + }); + }); + return () => stop(); + }, +}; + +export default plugin; diff --git a/src/v2/index.ts b/src/v2/index.ts new file mode 100644 index 0000000..efcc31e --- /dev/null +++ b/src/v2/index.ts @@ -0,0 +1,4 @@ +// Compatibility alias for configs written as "opencode-supermemory/v2". +// OpenCode 2 normally resolves "opencode-supermemory/server" on its own. +export { default } from "../server.js"; +export { setupV2 } from "./runtime.js"; diff --git a/src/v2/runtime.test.ts b/src/v2/runtime.test.ts new file mode 100644 index 0000000..bb05a5a --- /dev/null +++ b/src/v2/runtime.test.ts @@ -0,0 +1,466 @@ +import { describe, expect, test } from "bun:test"; + +import { COMPACTION_CONTEXT_MARKER } from "../services/compaction-prompt.js"; +import { executeSupermemoryTool } from "../services/memory-tool.js"; +import { DEFAULT_RECALL_DIRECTIVE } from "../services/recall.js"; +import type { ResolvedTags } from "../services/tags.js"; +import { + applyInjection, + buildTranscriptTurns, + buildV2RecallDirective, + mergeTurns, + SUPERMEMORY_RECALL_TOOL_NAME, + SUPERMEMORY_TOOL_NAME, + V2Runtime, + type RequestMessage, + type TranscriptMessage, + type V2Context, + type V2RuntimeDependencies, +} from "./runtime.js"; + +const tags: ResolvedTags = { + canonical: "repo_test__0123456789abcdef", + user: "repo_test__0123456789abcdef", + project: "repo_test__0123456789abcdef", + projectId: "0123456789abcdef", + projectName: "test", + personalReads: [], + projectReads: [], + allReads: [], +}; + +function user(id: string, text: string): TranscriptMessage { + return { id, type: "user", text }; +} + +function assistant( + id: string, + text: string, + finish: string = "stop", +): TranscriptMessage { + return { id, type: "assistant", finish, content: [{ type: "text", text }] }; +} + +function request(id: string, text: string): RequestMessage { + return { + id, + role: "user", + content: [{ type: "text", text }], + } as unknown as RequestMessage; +} + +function texts(message: RequestMessage): string[] { + return (message.content as Array<{ type: string; text?: string }>).map( + (part) => part.text ?? "", + ); +} + +describe("OpenCode 2 transcript capture", () => { + test("groups completed turns and protects private content", () => { + const turns = buildTranscriptTurns([ + { id: "sys", type: "system", text: "injected" }, + user("u1", "real prompt"), + assistant("a1", "calling a tool", "tool-calls"), + assistant("a2", "real answer"), + user("u2", "secret prompt"), + assistant("a3", "secret answer"), + user("u3", "token secret"), + assistant("a4", "safe answer"), + user("u4", "still streaming"), + ]); + + expect(turns.map((turn) => turn.id)).toEqual(["u1", "u2", "u3"]); + expect(turns[0]?.messages).toEqual([ + { role: "user", content: "real prompt" }, + { role: "assistant", content: "calling a tool" }, + { role: "assistant", content: "real answer" }, + ]); + expect(turns[1]?.messages).toEqual([]); + expect(turns[2]?.messages[0]).toEqual({ + role: "user", + content: "token [REDACTED]", + }); + }); + + test("keeps turn positions stable when the transcript is compacted", () => { + const existing = mergeTurns( + [], + new Map(), + buildTranscriptTurns([user("u1", "one"), assistant("a1", "1")]), + ); + const index = new Map([["u1", 0]]); + mergeTurns( + existing, + index, + buildTranscriptTurns([user("u2", "two"), assistant("a2", "2")]), + ); + expect(existing.map((turn) => turn.id)).toEqual(["u1", "u2"]); + }); +}); + +describe("OpenCode 2 request injection", () => { + test("points the advisory directive at the recall helper", () => { + const directive = buildV2RecallDirective(DEFAULT_RECALL_DIRECTIVE); + expect(directive).toContain(`\`${SUPERMEMORY_RECALL_TOOL_NAME}\` tool`); + expect(directive).not.toContain('`supermemory` tool with `mode: "search"`'); + }); + + test("injects once per request copy and survives frozen messages", () => { + const message = request("u1", "hello"); + applyInjection([message], message, { start: ["profile"], end: ["recall"] }); + applyInjection([message], message, { start: ["profile"], end: ["recall"] }); + expect(texts(message)).toEqual(["profile", "hello", "recall"]); + + const frozen = request("u2", "frozen"); + Object.freeze(frozen.content); + const messages = [frozen]; + applyInjection(messages, frozen, { start: [], end: ["recall"] }); + expect(texts(messages[0]!)).toEqual(["frozen", "recall"]); + }); +}); + +interface FakeTool { + name: string; + execute: (input: unknown, context: unknown) => Promise<{ content?: unknown }>; +} + +interface Harness { + ctx: V2Context; + runtime: V2Runtime; + tools: Map; + hooks: Record Promise | void>; + queries: string[]; + writes: Array<{ customId?: string; timeoutMs?: number; metadata?: Record }>; + adds: Array<{ content: string; customId?: string; metadata?: Record }>; + emitted: Array<{ kind?: unknown; message?: unknown }>; + transcript: TranscriptMessage[]; +} + +function harness( + config: Partial = {}, +): Harness { + const tools = new Map(); + const hooks: Harness["hooks"] = {}; + const queries: string[] = []; + const writes: Harness["writes"] = []; + const adds: Harness["adds"] = []; + const emitted: Harness["emitted"] = []; + const state: { transcript: TranscriptMessage[] } = { transcript: [] }; + const registration = { dispose: async () => undefined }; + + const ctx = { + location: { directory: "/repo" }, + tool: { + transform: async (callback: (editor: unknown) => void) => { + callback({ + add: (tool: FakeTool) => { + tools.set(tool.name, tool); + }, + list: () => [], + get: () => undefined, + namespace: () => undefined, + update: () => undefined, + remove: () => undefined, + }); + return registration; + }, + hook: async (name: string, callback: Harness["hooks"][string]) => { + hooks[`tool.${name}`] = callback; + return registration; + }, + reload: async () => undefined, + list: async () => [], + }, + session: { + hook: async (name: string, callback: Harness["hooks"][string]) => { + hooks[`session.${name}`] = callback; + return registration; + }, + get: async ({ sessionID }: { sessionID: string }) => ({ + id: sessionID, + location: { directory: "/repo" }, + }), + context: async () => state.transcript, + }, + permission: { + hook: async (name: string, callback: Harness["hooks"][string]) => { + hooks[`permission.${name}`] = callback; + return registration; + }, + }, + rpc: { + register: async () => ({ + ...registration, + events: { + emit: async (_name: string, data: Record) => { + emitted.push(data); + }, + }, + }), + }, + event: { + subscribe: () => ({ + [Symbol.asyncIterator]: () => ({ + next: () => new Promise>(() => undefined), + }), + }), + }, + }; + + const memoryClient = { + getProfileScoped: async () => ({ + success: true, + profile: { static: ["Prefers bun"], dynamic: [] }, + }), + searchMemoriesForRecall: async (query: string) => { + queries.push(query); + return { + success: true, + results: [{ memory: "Uses bun, not Node.js", similarity: 0.9 }], + }; + }, + searchMemoriesScoped: async () => ({ success: true, results: [] }), + searchMemoriesMany: async () => ({ + success: true, + results: [{ id: "m1", memory: "Uses bun, not Node.js", similarity: 0.9 }], + }), + listMemoriesScoped: async () => ({ + success: true, + memories: [{ summary: "Build: bun run build" }], + }), + ingestConversation: async ( + _conversationId: string, + _messages: unknown, + _containerTags: string[], + metadata?: Record, + options?: { customId?: string; timeoutMs?: number }, + ) => { + writes.push({ customId: options?.customId, timeoutMs: options?.timeoutMs, metadata }); + return { success: true }; + }, + addMemory: async ( + content: string, + _containerTag: string, + metadata?: Record, + options?: { customId?: string }, + ) => { + adds.push({ content, customId: options?.customId, metadata }); + return { success: true, id: "mem_1" }; + }, + deleteMemory: async () => ({ success: true }), + }; + + const runtime = new V2Runtime(ctx as unknown as V2Context, { + configured: true, + config: { + recallMode: "direct", + injectProfile: true, + captureEveryNTurns: 1, + compactionEnabled: true, + keywordPatterns: ["remember"], + maxProjectMemories: 10, + ...config, + }, + memoryClient: memoryClient as unknown as V2RuntimeDependencies["memoryClient"], + executeTool: executeSupermemoryTool, + resolveTags: () => tags, + logger: () => undefined, + checkUpdate: async () => ({ + currentVersion: "2.0.15", + latestVersion: "9.9.9", + updateCommand: "bunx opencode-supermemory@latest install", + }), + }); + + return { + ctx: ctx as unknown as V2Context, + runtime, + tools, + hooks, + queries, + writes, + adds, + emitted, + get transcript() { + return state.transcript; + }, + set transcript(value: TranscriptMessage[]) { + state.transcript = value; + }, + }; +} + +describe("OpenCode 2 runtime", () => { + test("registers tools and hooks, and auto-allows recall", async () => { + const h = harness(); + await h.runtime.register(); + + expect([...h.tools.keys()].sort()).toEqual([ + SUPERMEMORY_TOOL_NAME, + SUPERMEMORY_RECALL_TOOL_NAME, + ].sort()); + expect(Object.keys(h.hooks).sort()).toEqual([ + "permission.evaluate", + "session.compaction", + "session.context", + "tool.execute.after", + "tool.execute.before", + ]); + + const evaluation = { action: "supermemory_recall", effect: "ask" }; + await h.hooks["permission.evaluate"]!(evaluation); + expect(evaluation.effect).toBe("allow"); + + const other = { action: "supermemory", effect: "ask" }; + await h.hooks["permission.evaluate"]!(other); + expect(other.effect).toBe("ask"); + + const recall = h.tools.get(SUPERMEMORY_RECALL_TOOL_NAME)!; + const denied = JSON.parse( + String((await recall.execute({ mode: "add", content: "x" }, { sessionID: "s1" })).content), + ); + expect(denied.success).toBe(false); + const found = JSON.parse( + String((await recall.execute({ query: "bun" }, { sessionID: "s1" })).content), + ); + expect(found.count).toBe(1); + h.runtime.cleanup(); + }); + + test("injects profile and direct recall once per prompt, re-applied on continuations", async () => { + const h = harness(); + await h.runtime.register(); + + const first = request("u1", "continue the auth flow work from before"); + await h.runtime.handleContext({ sessionID: "s1", messages: [first] }); + const firstTexts = texts(first); + expect(firstTexts[0]).toContain("Prefers bun"); + expect(firstTexts.at(-1)).toContain("Uses bun, not Node.js"); + expect(firstTexts).not.toContain(expect.stringContaining("update available")); + + // Tool continuation: fresh request copy, same prompt, no second search. + const continuation = request("u1", "continue the auth flow work from before"); + await h.runtime.handleContext({ + sessionID: "s1", + messages: [continuation, { role: "assistant", content: [] } as unknown as RequestMessage], + }); + expect(texts(continuation)).toEqual(firstTexts); + expect(h.queries).toHaveLength(1); + + // New prompt: no profile again, repeated memory suppressed per session. + const second = request("u2", "remember that we deploy with bun"); + await h.runtime.handleContext({ + sessionID: "s1", + messages: [first, second], + }); + const secondTexts = texts(second); + expect(h.queries).toHaveLength(2); + expect(secondTexts[0]).toBe("remember that we deploy with bun"); + expect(secondTexts.some((text) => text.includes("[MEMORY TRIGGER DETECTED]"))).toBe(true); + expect(secondTexts.some((text) => text.includes("Uses bun, not Node.js"))).toBe(false); + + const kinds = h.emitted.map((event) => event.kind); + expect(kinds).toContain("recalled"); + expect(kinds).toContain("update-available"); + h.runtime.cleanup(); + }); + + test("advisory mode injects the recall directive instead of searching", async () => { + const h = harness({ recallMode: "advisory", injectProfile: false }); + await h.runtime.register(); + const message = request("u1", "what did we decide about caching?"); + await h.runtime.handleContext({ sessionID: "s1", messages: [message] }); + expect(texts(message).at(-1)).toContain(SUPERMEMORY_RECALL_TOOL_NAME); + expect(h.queries).toHaveLength(0); + h.runtime.cleanup(); + }); + + test("captures completed turns idempotently and saves compaction summaries", async () => { + const h = harness(); + await h.runtime.register(); + + h.transcript = [user("u1", "question 1"), assistant("a1", "answer 1")]; + await h.runtime.handleEvent({ + id: "e1", + type: "session.execution.succeeded", + data: { sessionID: "s1" }, + }); + await h.runtime.idle(); + await h.runtime.handleEvent({ + id: "e2", + type: "session.execution.succeeded", + data: { sessionID: "s1" }, + }); + await h.runtime.idle(); + expect(h.writes).toHaveLength(1); + expect(h.writes[0]?.customId).toStartWith("opencode:capture:"); + expect(h.writes[0]?.timeoutMs).toBe(3_000); + expect(h.writes[0]?.metadata).toMatchObject({ + captureReason: "cadence", + sm_capture_mode: "automatic", + }); + + // Compaction truncates the transcript; the earlier turn keeps its slot. + h.transcript = [ + { id: "c1", type: "compaction" }, + user("u2", "question 2"), + assistant("a2", "answer 2"), + ]; + await h.runtime.handleEvent({ + id: "e3", + type: "session.execution.succeeded", + data: { sessionID: "s1" }, + }); + await h.runtime.idle(); + expect(h.writes).toHaveLength(2); + expect(h.writes[1]?.customId).not.toBe(h.writes[0]?.customId); + + const summary = "Summary ".repeat(20); + await h.runtime.handleEvent({ + id: "e4", + type: "session.compaction.ended", + data: { sessionID: "s1", text: summary, reason: "auto" }, + }); + await h.runtime.handleEvent({ + id: "e4", + type: "session.compaction.ended", + data: { sessionID: "s1", text: summary, reason: "auto" }, + }); + expect(h.adds).toHaveLength(1); + expect(h.adds[0]?.customId).toStartWith("opencode:compaction:"); + expect(h.adds[0]?.metadata).toMatchObject({ sm_capture_mode: "compaction" }); + + const system: Array<{ type: "text"; text: string }> = []; + await h.runtime.handleCompaction({ sessionID: "s1", system }); + expect(system[0]?.text).toContain(COMPACTION_CONTEXT_MARKER); + expect(system[0]?.text).toContain("Build: bun run build"); + + await h.runtime.handleEvent({ + id: "e5", + type: "session.deleted", + data: { sessionID: "s1" }, + }); + expect(h.runtime.trackedSessionCount).toBe(0); + expect(h.writes).toHaveLength(2); + expect(h.emitted.filter((event) => event.kind === "saved")).toHaveLength(3); + h.runtime.cleanup(); + }); + + test("reports tool-driven recall activity", async () => { + const h = harness(); + await h.runtime.register(); + await h.hooks["tool.execute.before"]!({ + tool: SUPERMEMORY_TOOL_NAME, + input: { mode: "search", query: "auth" }, + }); + await h.hooks["tool.execute.after"]!({ + tool: SUPERMEMORY_RECALL_TOOL_NAME, + status: "completed", + result: { + content: JSON.stringify({ success: true, query: "auth", count: 2, results: [{}, {}] }), + }, + }); + expect(h.emitted.map((event) => event.kind)).toEqual(["recalling", "recalled"]); + h.runtime.cleanup(); + }); +}); diff --git a/src/v2/runtime.ts b/src/v2/runtime.ts new file mode 100644 index 0000000..2fee56b --- /dev/null +++ b/src/v2/runtime.ts @@ -0,0 +1,1308 @@ +import { createHash } from "node:crypto"; + +import type { Plugin } from "@opencode/plugin"; +import type { SessionHooks } from "@opencode/plugin/promise/session"; + +import { CONFIG, isConfigured, PLUGIN_VERSION } from "../config.js"; +import { + createMemoryActivityReporterFromSink, + type MemoryActivityNotice, + type MemoryActivityReporter, +} from "../services/activity.js"; +import { + AUTOMATIC_CAPTURE_TIMEOUT_MS, + buildCadenceBatches, + buildSessionEndBatch, + getCaptureId, + type CaptureBatch, + type CaptureTurn, +} from "../services/capture.js"; +import { supermemoryClient, type SupermemoryClient } from "../services/client.js"; +import { + createCompactionPrompt, + fitProjectMemories, +} from "../services/compaction-prompt.js"; +import { + formatContextForPrompt, + getInjectedProfileFactTexts, +} from "../services/context.js"; +import { AGENT_ENTITY_CONTEXT } from "../services/entity-context.js"; +import { log } from "../services/logger.js"; +import { + executeSupermemoryTool, + MEMORY_TOOL_MODES, + MEMORY_TOOL_SCOPES, + MEMORY_TOOL_TYPES, + SUPERMEMORY_RECALL_TOOL_DESCRIPTION, + SUPERMEMORY_TOOL_DESCRIPTION, + type SupermemoryToolArgs, +} from "../services/memory-tool.js"; +import { RECALL_PERMISSION } from "../services/opencode-permissions.js"; +import { isFullyPrivate, stripPrivateContent } from "../services/privacy.js"; +import { + buildDirectRecallResult, + buildRecallDirective, + DIRECT_RECALL_TIMEOUT_MS, + RecallSessionCache, + type DirectRecallResult, +} from "../services/recall.js"; +import { getTags, type ResolvedTags } from "../services/tags.js"; +import { checkNpmUpdate, type UpdateInfo } from "../services/version-check.js"; +import { SUPERMEMORY_RPC } from "../rpc.js"; + +export type V2Context = Plugin.Context; +type SessionContextEvent = SessionHooks["context"]; +type SessionCompactionEvent = SessionHooks["compaction"]; +export type RequestMessage = SessionContextEvent["messages"][number]; +type RequestContentPart = RequestMessage["content"][number]; + +const CODE_BLOCK_PATTERN = /```[\s\S]*?```/g; +const INLINE_CODE_PATTERN = /`[^`]+`/g; +const SYNTHETIC_METADATA_KEY = "supermemory"; +const UPDATE_COMMAND = "bunx opencode-supermemory@latest install"; +const MAX_DISPATCHES_PER_SESSION = 8; +const MIN_SUMMARY_CHARS = 100; + +export const SUPERMEMORY_TOOL_NAME = "supermemory"; +export const SUPERMEMORY_RECALL_TOOL_NAME = "supermemory_recall"; + +export const MEMORY_NUDGE_MESSAGE = `[MEMORY TRIGGER DETECTED] +The user wants you to remember something. You MUST use the \`supermemory\` tool with \`mode: "add"\` to save this information. + +Extract the key information the user wants remembered and save it as a concise, searchable memory. +- Use \`scope: "project"\` for project-specific preferences (e.g., "run lint with tests") +- Use \`scope: "user"\` for personal preferences in this project (e.g., "prefers concise responses") +- Choose an appropriate \`type\`: "preference", "project-config", "learned-pattern", etc. + +DO NOT skip this step. The user explicitly asked you to remember.`; + +export const SUPERMEMORY_TOOL_INPUT = { + type: "object", + additionalProperties: false, + properties: { + mode: { type: "string", enum: [...MEMORY_TOOL_MODES] }, + content: { type: "string" }, + query: { type: "string" }, + type: { type: "string", enum: [...MEMORY_TOOL_TYPES] }, + scope: { type: "string", enum: [...MEMORY_TOOL_SCOPES] }, + memoryId: { type: "string" }, + limit: { type: "number" }, + }, +} as const; + +export const SUPERMEMORY_RECALL_INPUT = { + type: "object", + additionalProperties: false, + properties: { + mode: { type: "string", enum: ["search"] }, + query: { type: "string" }, + scope: { type: "string", enum: [...MEMORY_TOOL_SCOPES] }, + limit: { type: "number" }, + }, + required: ["query"], +} as const; + +type RuntimeMemoryClient = Pick< + SupermemoryClient, + | "addMemory" + | "ingestConversation" + | "getProfileScoped" + | "searchMemoriesForRecall" + | "searchMemoriesScoped" + | "searchMemoriesMany" + | "listMemoriesScoped" + | "deleteMemory" +>; + +type RuntimeConfig = Pick< + typeof CONFIG, + | "recallMode" + | "injectProfile" + | "captureEveryNTurns" + | "compactionEnabled" + | "keywordPatterns" + | "maxProjectMemories" +>; + +export interface V2RuntimeDependencies { + configured: boolean; + config: RuntimeConfig; + memoryClient: RuntimeMemoryClient; + executeTool: typeof executeSupermemoryTool; + resolveTags: typeof getTags; + logger: typeof log; + checkUpdate: () => Promise; +} + +const DEFAULT_DEPENDENCIES: V2RuntimeDependencies = { + configured: isConfigured(), + config: CONFIG, + memoryClient: supermemoryClient, + executeTool: executeSupermemoryTool, + resolveTags: getTags, + logger: log, + checkUpdate: () => + checkNpmUpdate("opencode-supermemory", PLUGIN_VERSION, UPDATE_COMMAND), +}; + +/** Minimal shape of an OpenCode 2 event as read from `ctx.event.subscribe()`. */ +export interface V2Event { + id?: string; + type: string; + data?: Record; +} + +/** Minimal shape of a persisted OpenCode 2 transcript message. */ +export interface TranscriptMessage { + id: string; + type: string; + text?: string; + finish?: string; + content?: ReadonlyArray<{ type: string; text?: string }>; +} + +interface Injection { + start: string[]; + end: string[]; +} + +interface SessionState { + directory?: string; + tags?: ResolvedTags; + resolving?: Promise; + injectedInitialContext: boolean; + dispatches: Map>; + dispatchOrder: string[]; + turns: CaptureTurn[]; + turnIndex: Map; + completedCaptureIds: Set; +} + +interface PendingSummary { + customId: string; + sessionID: string; + text: string; +} + +interface Registration { + dispose: () => Promise; +} + +function mergeDependencies( + overrides: Partial | undefined, +): V2RuntimeDependencies { + return { + ...DEFAULT_DEPENDENCIES, + ...overrides, + config: { ...DEFAULT_DEPENDENCIES.config, ...overrides?.config }, + }; +} + +function sha256(value: string): string { + return createHash("sha256").update(value).digest("hex"); +} + +function removeCodeBlocks(text: string): string { + return text.replace(CODE_BLOCK_PATTERN, "").replace(INLINE_CODE_PATTERN, ""); +} + +export function detectMemoryKeyword( + text: string, + patterns: readonly string[] = CONFIG.keywordPatterns, +): boolean { + if (patterns.length === 0) return false; + return new RegExp(`\\b(${patterns.join("|")})\\b`, "i").test( + removeCodeBlocks(text), + ); +} + +/** + * OpenCode 2 exposes the search-only `supermemory_recall` helper, so the + * advisory directive points the model at it instead of the full tool. + */ +export function buildV2RecallDirective( + directive: string = buildRecallDirective(), +): string { + return directive.replaceAll( + `\`${SUPERMEMORY_TOOL_NAME}\` tool with \`mode: "search"\``, + `\`${SUPERMEMORY_RECALL_TOOL_NAME}\` tool`, + ); +} + +function isSyntheticPart(part: unknown): boolean { + if (!part || typeof part !== "object") return false; + const metadata = (part as { metadata?: Record }).metadata; + return Boolean(metadata?.[SYNTHETIC_METADATA_KEY]); +} + +export function extractMessageText(message: { + content: ReadonlyArray; +}): string { + return message.content + .filter( + (part): part is { type: "text"; text: string } => + Boolean(part) && + typeof part === "object" && + (part as { type?: unknown }).type === "text" && + typeof (part as { text?: unknown }).text === "string" && + !isSyntheticPart(part), + ) + .map((part) => part.text) + .join("\n") + .trim(); +} + +function makeSyntheticPart(text: string, kind: string): RequestContentPart { + return { + type: "text", + text, + metadata: { [SYNTHETIC_METADATA_KEY]: kind }, + } as RequestContentPart; +} + +/** + * Adds plugin context to the outgoing copy of the latest user message. Hook + * messages are request-local, so the same injection is re-applied on every + * model call for the same prompt (including tool continuations). + */ +export function applyInjection( + messages: RequestMessage[], + message: RequestMessage, + injection: Injection, +): void { + if (injection.start.length === 0 && injection.end.length === 0) return; + if (message.content.some(isSyntheticPart)) return; + + const start = injection.start.map((text) => makeSyntheticPart(text, "context")); + const end = injection.end.map((text) => makeSyntheticPart(text, "recall")); + + try { + const content = message.content as RequestContentPart[]; + content.unshift(...start); + content.push(...end); + } catch { + // Frozen request messages: replace the message with a copy that keeps + // its prototype so downstream encoding still recognises it. + const index = messages.indexOf(message); + if (index < 0) return; + const copy = Object.assign( + Object.create(Object.getPrototypeOf(message) as object | null), + message, + { content: [...start, ...message.content, ...end] }, + ) as RequestMessage; + messages[index] = copy; + } +} + +function sanitizeCaptureText(text: string): string { + if (!text || isFullyPrivate(text)) return ""; + return stripPrivateContent(text).trim(); +} + +function isFinalAssistant(message: TranscriptMessage): boolean { + return ( + typeof message.finish === "string" && + message.finish.length > 0 && + message.finish !== "tool-calls" + ); +} + +function assistantText(message: TranscriptMessage): string { + return (message.content ?? []) + .filter((part) => part.type === "text" && typeof part.text === "string") + .map((part) => part.text as string) + .join("\n") + .trim(); +} + +/** + * Groups an OpenCode 2 transcript into completed user/assistant turns using + * the same rules as the V1 capture hook: synthetic and system messages are + * ignored, `` content is redacted, and a fully private prompt hides + * its whole turn. + */ +export function buildTranscriptTurns( + messages: ReadonlyArray, +): CaptureTurn[] { + const turns: CaptureTurn[] = []; + let current: + | { + id: string; + messages: CaptureTurn["messages"]; + fullyPrivate: boolean; + complete: boolean; + } + | undefined; + + const finish = () => { + if (current?.complete) { + turns.push({ + id: current.id, + messages: current.fullyPrivate ? [] : current.messages, + }); + } + current = undefined; + }; + + for (const message of messages) { + if (message.type === "user") { + finish(); + const rawText = (message.text ?? "").trim(); + const text = sanitizeCaptureText(rawText); + current = { + id: message.id, + messages: text ? [{ role: "user", content: text }] : [], + fullyPrivate: rawText.length > 0 && isFullyPrivate(rawText), + complete: false, + }; + continue; + } + + if (!current || message.type !== "assistant") continue; + + const text = sanitizeCaptureText(assistantText(message)); + if (text && !current.fullyPrivate) { + current.messages.push({ role: "assistant", content: text }); + } + if (isFinalAssistant(message)) current.complete = true; + } + + finish(); + return turns; +} + +/** + * Merges freshly read turns into the session's cumulative turn list. The + * transcript OpenCode returns may shrink after compaction, so turn positions + * (and therefore capture IDs) are anchored to the first time a turn was seen. + */ +export function mergeTurns( + existing: CaptureTurn[], + index: Map, + incoming: CaptureTurn[], +): CaptureTurn[] { + for (const turn of incoming) { + const position = index.get(turn.id); + if (position === undefined) { + index.set(turn.id, existing.length); + existing.push(turn); + } else { + existing[position] = turn; + } + } + return existing; +} + +export class EventDeduper { + readonly #limit: number; + readonly #seen = new Set(); + readonly #order: string[] = []; + + constructor(limit = 4_096) { + this.#limit = Math.max(1, limit); + } + + hasSeen(id: string | undefined): boolean { + if (!id) return false; + if (this.#seen.has(id)) return true; + this.#seen.add(id); + this.#order.push(id); + if (this.#order.length > this.#limit) { + const oldest = this.#order.shift(); + if (oldest) this.#seen.delete(oldest); + } + return false; + } +} + +function toolResultText(content: unknown): string { + if (typeof content === "string") return content; + if (Array.isArray(content)) { + return content + .filter( + (part): part is { type: "text"; text: string } => + Boolean(part) && + typeof part === "object" && + (part as { type?: unknown }).type === "text" && + typeof (part as { text?: unknown }).text === "string", + ) + .map((part) => part.text) + .join("\n"); + } + return ""; +} + +export class V2Runtime { + readonly #ctx: V2Context; + readonly #deps: V2RuntimeDependencies; + readonly #isOwner: () => boolean; + readonly #states = new Map(); + readonly #recall = new RecallSessionCache(); + readonly #captureInFlight = new Map>(); + readonly #pendingSummaries = new Map(); + readonly #summaryInFlight = new Set(); + readonly #deduper = new EventDeduper(); + readonly #registrations: Registration[] = []; + readonly #abortController = new AbortController(); + #emitActivity: ((notice: MemoryActivityNotice) => void) | undefined; + #activity: MemoryActivityReporter; + #active = true; + + constructor( + ctx: V2Context, + options?: Partial, + isOwner: () => boolean = () => true, + ) { + this.#ctx = ctx; + this.#deps = mergeDependencies(options); + this.#isOwner = isOwner; + this.#activity = createMemoryActivityReporterFromSink((notice) => { + this.#deps.logger("[activity]", { kind: notice.kind, message: notice.message }); + this.#emitActivity?.(notice); + }); + } + + get active(): boolean { + return this.#active && this.#isOwner(); + } + + get trackedSessionCount(): number { + return this.#states.size; + } + + async register(): Promise { + const { logger } = this.#deps; + + await this.#track( + this.#ctx.tool.transform((editor) => { + editor.add({ + name: SUPERMEMORY_TOOL_NAME, + description: SUPERMEMORY_TOOL_DESCRIPTION, + input: SUPERMEMORY_TOOL_INPUT, + options: { codemode: false, permission: SUPERMEMORY_TOOL_NAME }, + execute: async (input, context) => { + if (!this.active) return { content: this.#inactiveToolResult() }; + return { + content: await this.executeTool( + input as SupermemoryToolArgs, + context.sessionID, + ), + }; + }, + }); + + editor.add({ + name: SUPERMEMORY_RECALL_TOOL_NAME, + description: SUPERMEMORY_RECALL_TOOL_DESCRIPTION, + input: SUPERMEMORY_RECALL_INPUT, + options: { codemode: false, permission: RECALL_PERMISSION.action }, + execute: async (input, context) => { + if (!this.active) return { content: this.#inactiveToolResult() }; + return { + content: await this.executeRecallTool( + input as SupermemoryToolArgs, + context.sessionID, + ), + }; + }, + }); + }), + ); + if (!this.active) return; + + if (!this.#deps.configured) { + logger("v2 plugin disabled - SUPERMEMORY_API_KEY not set (tools registered, hooks skipped)"); + return; + } + + await this.#track( + this.#ctx.session.hook("context", async (event) => { + if (!this.active) return; + await this.handleContext(event); + }), + ); + if (!this.active) return; + + await this.#track( + this.#ctx.session.hook("compaction", async (event) => { + if (!this.active) return; + await this.handleCompaction(event); + }), + ); + if (!this.active) return; + + // Mirror the V1 `permission.ask` auto-allow: recall is read-only. + await this.#track( + this.#ctx.permission.hook("evaluate", (event) => { + if (!this.active) return; + if (event.action === RECALL_PERMISSION.action && event.effect === "ask") { + event.effect = "allow"; + } + }), + ); + if (!this.active) return; + + await this.#track( + this.#ctx.tool.hook("execute.before", (event) => { + if (!this.active) return; + this.handleToolBefore(event.tool, event.input); + }), + ); + await this.#track( + this.#ctx.tool.hook("execute.after", (event) => { + if (!this.active) return; + if (event.status !== "completed") return; + this.handleToolAfter(event.tool, toolResultText(event.result.content)); + }), + ); + if (!this.active) return; + + try { + const rpc = await this.#ctx.rpc.register(SUPERMEMORY_RPC, {}); + this.#registrations.push(rpc); + this.#emitActivity = (notice) => { + void rpc.events + .emit("activity", { + kind: notice.kind, + title: notice.title, + message: notice.message, + variant: notice.variant, + duration: notice.duration, + }) + .catch((error) => { + logger("[activity] unable to emit notice", { error: String(error) }); + }); + }; + } catch (error) { + logger("[activity] RPC unavailable; notices are log-only", { + error: String(error), + }); + } + + if (this.active) this.#startEventSubscription(); + logger("v2 plugin registered", { + tools: [SUPERMEMORY_TOOL_NAME, SUPERMEMORY_RECALL_TOOL_NAME], + hooks: ["session.context", "session.compaction", "permission.evaluate", "tool.execute"], + activity: this.#emitActivity ? "rpc" : "log-only", + recallMode: this.#deps.config.recallMode, + captureEveryNTurns: this.#deps.config.captureEveryNTurns, + compactionEnabled: this.#deps.config.compactionEnabled, + }); + } + + async executeTool(args: SupermemoryToolArgs, sessionID: string): Promise { + try { + const tags = await this.#resolveSession(sessionID); + return await this.#deps.executeTool(args, tags, { + memoryClient: this.#deps.memoryClient, + configured: this.#deps.configured, + onSaved: () => this.#activity.saved(), + }); + } catch (error) { + return JSON.stringify({ + success: false, + error: error instanceof Error ? error.message : String(error), + }); + } + } + + async executeRecallTool( + args: SupermemoryToolArgs, + sessionID: string, + ): Promise { + if (args.mode && args.mode !== "search") { + return JSON.stringify({ + success: false, + error: `${SUPERMEMORY_RECALL_TOOL_NAME} only supports search mode`, + }); + } + return this.executeTool({ ...args, mode: "search" }, sessionID); + } + + handleToolBefore(tool: string, input: unknown): void { + const args = (input ?? {}) as { mode?: unknown; query?: unknown }; + const isRecall = + tool === SUPERMEMORY_RECALL_TOOL_NAME || + (tool === SUPERMEMORY_TOOL_NAME && args.mode === "search"); + if (!isRecall) return; + this.#activity.recalling( + typeof args.query === "string" ? args.query : undefined, + ); + } + + handleToolAfter(tool: string, output: string): void { + if (tool !== SUPERMEMORY_TOOL_NAME && tool !== SUPERMEMORY_RECALL_TOOL_NAME) { + return; + } + try { + const result = JSON.parse(output) as { + success?: boolean; + query?: unknown; + count?: number; + results?: unknown[]; + }; + if (!result.success || result.query === undefined) return; + const count = result.count ?? result.results?.length; + if (typeof count === "number" && count > 0) { + this.#activity.recalled(count, Math.round(output.length / 4)); + } + } catch { + // Tool output remains authoritative when it is not structured JSON. + } + } + + async handleContext(event: { + sessionID: string; + messages: RequestMessage[]; + }): Promise { + if (!this.#deps.configured) return; + const latestUser = event.messages.findLast((message) => message.role === "user"); + if (!latestUser) return; + const userText = extractMessageText(latestUser); + if (!userText) return; + + const state = this.#state(event.sessionID); + const key = this.#dispatchKey(event.messages, latestUser, userText); + let pending = state.dispatches.get(key); + if (!pending) { + pending = this.#buildInjection(event.sessionID, state, userText).catch( + (error): Injection => { + this.#deps.logger("v2 context injection failed", { + sessionID: event.sessionID, + error: String(error), + }); + return { start: [], end: [] }; + }, + ); + state.dispatches.set(key, pending); + state.dispatchOrder.push(key); + while (state.dispatchOrder.length > MAX_DISPATCHES_PER_SESSION) { + const oldest = state.dispatchOrder.shift(); + if (oldest) state.dispatches.delete(oldest); + } + } + + applyInjection(event.messages, latestUser, await pending); + } + + async handleCompaction(event: { + sessionID: string; + system: Array<{ type: "text"; text: string }>; + }): Promise { + if (!this.#deps.configured || !this.#deps.config.compactionEnabled) return; + const memories = await this.#projectMemories(event.sessionID); + event.system.push({ type: "text", text: createCompactionPrompt(memories) }); + this.#deps.logger("v2 compaction context injected", { + sessionID: event.sessionID, + memoriesCount: memories.length, + }); + } + + async handleEvent(event: V2Event): Promise { + if (!this.active || this.#deduper.hasSeen(event.id)) return; + const sessionID = this.#eventSessionID(event); + + if (sessionID && event.type !== "session.compaction.ended") { + void this.#retryPendingSummaries(sessionID); + } + + switch (event.type) { + case "session.execution.succeeded": { + if (!sessionID) return; + void this.#runCaptureExclusive(sessionID, () => + this.#captureCadence(sessionID), + ); + return; + } + + case "session.execution.interrupted": { + if (!sessionID || event.data?.reason !== "shutdown") return; + if (!this.#states.has(sessionID)) return; + void this.#runCaptureExclusive(sessionID, () => + this.#captureSessionEnd(sessionID), + ); + return; + } + + case "session.deleted": { + if (!sessionID) return; + const state = this.#states.get(sessionID); + this.#recall.delete(sessionID); + if (!state) return; + await this.#runCaptureExclusive(sessionID, () => + this.#captureSessionEnd(sessionID), + ); + this.#states.delete(sessionID); + return; + } + + case "session.compaction.ended": { + if (!sessionID || !this.#deps.config.compactionEnabled) return; + const text = String(event.data?.text ?? "").trim(); + if (!text) return; + if (text.length < MIN_SUMMARY_CHARS) { + this.#deps.logger("v2 compaction summary too short to save", { + sessionID, + length: text.length, + }); + return; + } + const eventId = event.id ?? sha256(`${sessionID}:${text}`); + const customId = `opencode:compaction:${sha256(`${sessionID}:${eventId}`)}`; + this.#pendingSummaries.set(customId, { customId, sessionID, text }); + await this.#retryPendingSummaries(sessionID); + return; + } + + case "global.disposed": { + await this.#flushAll(); + this.#states.clear(); + this.#recall.clear(); + return; + } + } + } + + /** Waits for background capture and summary work; used by tests and shutdown. */ + async idle(): Promise { + while (this.#captureInFlight.size > 0 || this.#summaryInFlight.size > 0) { + await Promise.allSettled([...this.#captureInFlight.values()]); + if (this.#summaryInFlight.size > 0) { + await new Promise((resolve) => setTimeout(resolve, 5)); + } + } + } + + cleanup(): void { + if (!this.#active) return; + this.#active = false; + this.#abortController.abort(); + + void this.#flushAll(true).catch((error) => { + this.#deps.logger("v2 cleanup capture failed", { error: String(error) }); + }); + this.#states.clear(); + this.#recall.clear(); + + for (const registration of this.#registrations.splice(0)) { + this.#disposeRegistration(registration); + } + } + + async #track(pending: Promise): Promise { + const registration = await pending; + if (!this.active) { + this.#disposeRegistration(registration); + return; + } + this.#registrations.push(registration); + } + + #state(sessionID: string): SessionState { + const existing = this.#states.get(sessionID); + if (existing) return existing; + const state: SessionState = { + injectedInitialContext: false, + dispatches: new Map(), + dispatchOrder: [], + turns: [], + turnIndex: new Map(), + completedCaptureIds: new Set(), + }; + this.#states.set(sessionID, state); + return state; + } + + #inactiveToolResult(): string { + return JSON.stringify({ + success: false, + error: "This Supermemory plugin instance has been replaced; retry the call.", + }); + } + + #disposeRegistration(registration: Registration): void { + try { + void registration.dispose().catch((error) => { + this.#deps.logger("v2 registration cleanup failed", { + error: String(error), + }); + }); + } catch (error) { + this.#deps.logger("v2 registration cleanup failed", { + error: String(error), + }); + } + } + + #dispatchKey( + messages: RequestMessage[], + latestUser: RequestMessage, + text: string, + ): string { + const id = (latestUser as { id?: string }).id; + if (id) return id; + const userCount = messages.filter((message) => message.role === "user").length; + return `dispatch:${userCount}:${sha256(text)}`; + } + + async #resolveSession(sessionID: string): Promise { + const state = this.#state(sessionID); + if (state.tags) return state.tags; + if (state.resolving) return state.resolving; + + state.resolving = (async () => { + let directory: string | undefined; + try { + const session = await this.#ctx.session.get({ sessionID }); + directory = (session as { location?: { directory?: string } }).location + ?.directory; + } catch (error) { + this.#deps.logger("v2 session lookup failed; using plugin location", { + sessionID, + error: String(error), + }); + } + directory ??= this.#ctx.location?.directory; + if (!directory) { + throw new Error(`Unable to resolve directory for OpenCode session ${sessionID}`); + } + state.directory = directory; + state.tags = this.#deps.resolveTags(directory); + return state.tags; + })(); + + try { + return await state.resolving; + } finally { + state.resolving = undefined; + } + } + + async #buildInjection( + sessionID: string, + state: SessionState, + userText: string, + ): Promise { + const { config, memoryClient } = this.#deps; + const start: string[] = []; + const end: string[] = []; + const isFirstMessage = !state.injectedInitialContext; + state.injectedInitialContext = true; + + if (detectMemoryKeyword(userText, config.keywordPatterns)) { + end.push(MEMORY_NUDGE_MESSAGE); + } + if (config.recallMode === "advisory") end.push(buildV2RecallDirective()); + + let tags: ResolvedTags; + try { + tags = await this.#resolveSession(sessionID); + } catch (error) { + this.#deps.logger("v2 context skipped; no session directory", { + sessionID, + error: String(error), + }); + return { start, end }; + } + + const profileRequest = + isFirstMessage && config.recallMode !== "off" && config.injectProfile + ? memoryClient + .getProfileScoped(tags.canonical, tags.personalReads, "personal", undefined, { + timeoutMs: DIRECT_RECALL_TIMEOUT_MS, + }) + .catch(() => null) + : Promise.resolve(null); + + const skipped: DirectRecallResult = { + context: "", + status: "skipped", + count: 0, + tokens: 0, + }; + const directRecall = + config.recallMode === "direct" + ? buildDirectRecallResult({ + prompt: userText, + sessionID, + cache: this.#recall, + search: (query) => + memoryClient.searchMemoriesForRecall( + query, + tags.canonical, + tags.personalReads, + tags.projectReads, + { timeoutMs: DIRECT_RECALL_TIMEOUT_MS }, + ), + suppressTexts: isFirstMessage + ? profileRequest.then((result) => + result?.success && result.profile + ? getInjectedProfileFactTexts(result) + : [], + ) + : undefined, + }) + : Promise.resolve(skipped); + + const firstMessage = isFirstMessage + ? profileRequest.then((result) => + result?.success + ? formatContextForPrompt(result, { results: [] }, { results: [] }) + : "", + ) + : Promise.resolve(""); + + const updateCheck = isFirstMessage + ? this.#deps.checkUpdate().catch(() => null) + : Promise.resolve(null); + + const [recall, firstMessageContext, updateInfo] = await Promise.all([ + directRecall, + firstMessage, + updateCheck, + ]); + + if (recall.status === "recalled") { + this.#activity.recalled(recall.count, recall.tokens); + } else if (recall.status === "unavailable") { + this.#activity.recallUnavailable(); + } + if (updateInfo) this.#activity.updateAvailable(updateInfo); + + if (firstMessageContext) start.push(firstMessageContext); + if (recall.context) end.push(recall.context); + + this.#deps.logger("v2 context prepared", { + sessionID, + firstMessage: isFirstMessage, + firstMessageContextLength: firstMessageContext.length, + directRecallContextLength: recall.context.length, + }); + return { start, end }; + } + + async #projectMemories(sessionID: string): Promise { + try { + const tags = await this.#resolveSession(sessionID); + const result = await this.#deps.memoryClient.listMemoriesScoped( + tags.canonical, + tags.projectReads, + "project", + this.#deps.config.maxProjectMemories, + ); + return fitProjectMemories( + (result.memories ?? []) + .map((memory) => memory.summary || memory.content || "") + .filter((memory): memory is string => Boolean(memory)), + ); + } catch (error) { + this.#deps.logger("v2 compaction project-memory lookup failed", { + sessionID, + error: String(error), + }); + return []; + } + } + + async #refreshTurns(sessionID: string, state: SessionState): Promise { + try { + const messages = (await this.#ctx.session.context({ sessionID })) as unknown; + if (Array.isArray(messages)) { + mergeTurns( + state.turns, + state.turnIndex, + buildTranscriptTurns(messages as TranscriptMessage[]), + ); + } + } catch (error) { + this.#deps.logger("v2 capture transcript read failed; using cached turns", { + sessionID, + error: String(error), + }); + } + return state.turns; + } + + async #saveBatch( + sessionID: string, + state: SessionState, + batch: CaptureBatch, + reason: "cadence" | "session_end", + ): Promise { + const captureId = getCaptureId(sessionID, batch); + if (state.completedCaptureIds.has(captureId)) return true; + const messages = batch.turns.flatMap((turn) => turn.messages); + if (messages.length === 0) { + state.completedCaptureIds.add(captureId); + return true; + } + + let result: { success: boolean; error?: string }; + try { + const tags = await this.#resolveSession(sessionID); + result = await this.#deps.memoryClient.ingestConversation( + `${sessionID}:${batch.startTurn}-${batch.endTurn}`, + messages, + [tags.canonical], + { + project: tags.projectName, + sm_project_id: tags.projectId, + sm_scope: "personal", + sm_capture_mode: "automatic", + captureReason: reason, + sessionId: sessionID, + turnStart: batch.startTurn, + turnEnd: batch.endTurn, + }, + { + defaultEntityContext: AGENT_ENTITY_CONTEXT, + customId: captureId, + timeoutMs: AUTOMATIC_CAPTURE_TIMEOUT_MS, + }, + ); + } catch (error) { + result = { + success: false, + error: error instanceof Error ? error.message : String(error), + }; + } + + if (result.success) { + state.completedCaptureIds.add(captureId); + this.#activity.saved(); + this.#deps.logger("[capture] conversation batch saved", { + sessionID, + reason, + startTurn: batch.startTurn, + endTurn: batch.endTurn, + }); + return true; + } + + this.#deps.logger("[capture] failed to save conversation batch", { + sessionID, + reason, + startTurn: batch.startTurn, + endTurn: batch.endTurn, + error: result.error, + }); + return false; + } + + async #captureCadence(sessionID: string): Promise { + const state = this.#state(sessionID); + const turns = await this.#refreshTurns(sessionID, state); + for (const batch of buildCadenceBatches( + turns, + this.#deps.config.captureEveryNTurns, + )) { + await this.#saveBatch(sessionID, state, batch, "cadence"); + } + } + + async #captureSessionEnd(sessionID: string): Promise { + const state = this.#state(sessionID); + const turns = await this.#refreshTurns(sessionID, state); + for (const batch of buildCadenceBatches( + turns, + this.#deps.config.captureEveryNTurns, + )) { + await this.#saveBatch(sessionID, state, batch, "cadence"); + } + const finalBatch = buildSessionEndBatch( + turns, + this.#deps.config.captureEveryNTurns, + ); + if (finalBatch) { + await this.#saveBatch(sessionID, state, finalBatch, "session_end"); + } + } + + async #flushAll(allowInactive = false): Promise { + const sessions = [...this.#states.keys()]; + const pending = new Set( + [...this.#pendingSummaries.values()].map((item) => item.sessionID), + ); + await Promise.all([ + ...sessions.map((sessionID) => + this.#runCaptureExclusive(sessionID, () => + this.#captureSessionEnd(sessionID), + ), + ), + ...[...pending].map((sessionID) => + this.#retryPendingSummaries(sessionID, allowInactive), + ), + ]); + } + + async #runCaptureExclusive( + sessionID: string, + task: () => Promise, + ): Promise { + const previous = this.#captureInFlight.get(sessionID) ?? Promise.resolve(); + const next = previous.catch(() => undefined).then(task); + this.#captureInFlight.set(sessionID, next); + try { + await next; + } catch (error) { + this.#deps.logger("[capture] background capture failed", { + sessionID, + error: String(error), + }); + } finally { + if (this.#captureInFlight.get(sessionID) === next) { + this.#captureInFlight.delete(sessionID); + } + } + } + + async #retryPendingSummaries( + sessionID: string, + allowInactive = false, + ): Promise { + if (!allowInactive && !this.active) return; + const pending = [...this.#pendingSummaries.values()].filter( + (item) => item.sessionID === sessionID, + ); + if (pending.length === 0) return; + + let tags: ResolvedTags; + try { + tags = await this.#resolveSession(sessionID); + } catch (error) { + this.#deps.logger("v2 compaction summary retry deferred", { + sessionID, + error: String(error), + }); + return; + } + + for (const summary of pending) { + if (this.#summaryInFlight.has(summary.customId)) continue; + this.#summaryInFlight.add(summary.customId); + try { + const result = await this.#deps.memoryClient.addMemory( + `[Session Summary]\n${summary.text}`, + tags.canonical, + { + type: "conversation", + project: tags.projectName, + sm_project_id: tags.projectId, + sm_scope: "personal", + sm_capture_mode: "compaction", + sessionId: sessionID, + }, + { + customId: summary.customId, + entityContext: AGENT_ENTITY_CONTEXT, + timeoutMs: AUTOMATIC_CAPTURE_TIMEOUT_MS, + }, + ); + if (result.success) { + this.#pendingSummaries.delete(summary.customId); + this.#activity.saved(); + this.#deps.logger("[compaction] summary saved as memory", { + sessionID, + memoryId: result.id, + }); + } else { + this.#deps.logger("[compaction] failed to save summary", { + sessionID, + error: result.error, + }); + } + } catch (error) { + this.#deps.logger("[compaction] failed to save summary", { + sessionID, + error: String(error), + }); + } finally { + this.#summaryInFlight.delete(summary.customId); + } + } + } + + #eventSessionID(event: V2Event): string | undefined { + const sessionID = event.data?.sessionID; + return typeof sessionID === "string" && sessionID ? sessionID : undefined; + } + + #startEventSubscription(): void { + const events = this.#ctx.event.subscribe({ + signal: this.#abortController.signal, + }); + void (async () => { + try { + for await (const event of events as AsyncIterable) { + if (!this.active) return; + try { + await this.handleEvent(event); + } catch (error) { + this.#deps.logger("v2 event handling failed", { + type: event.type, + error: String(error), + }); + } + } + } catch (error) { + if (this.active) { + this.#deps.logger("v2 event subscription failed", { + error: String(error), + }); + } + } + })(); + } +} + +const OWNER_KEY = Symbol.for("opencode-supermemory.v2.owner"); + +interface GlobalOwner { + generation: number; + cleanup: () => void; +} + +function ownerRegistry(): Record { + return globalThis as unknown as Record; +} + +/** + * Starts the OpenCode 2 runtime. Only one instance is active per process, so a + * hot-reloaded plugin replaces (and cleans up) the previous generation. + */ +export async function setupV2( + ctx: V2Context, + options?: Partial, +): Promise<() => void> { + const registry = ownerRegistry(); + const previous = registry[OWNER_KEY]; + previous?.cleanup(); + + const owner: GlobalOwner = { + generation: (previous?.generation ?? 0) + 1, + cleanup: () => undefined, + }; + registry[OWNER_KEY] = owner; + + const runtime = new V2Runtime(ctx, options, () => registry[OWNER_KEY] === owner); + const cleanup = () => { + runtime.cleanup(); + if (registry[OWNER_KEY] === owner) delete registry[OWNER_KEY]; + }; + owner.cleanup = cleanup; + + log("v2 plugin init", { + generation: owner.generation, + directory: ctx.location?.directory, + configured: runtime["active"] && (options?.configured ?? isConfigured()), + }); + + try { + await runtime.register(); + } catch (error) { + cleanup(); + throw error; + } + + return cleanup; +} diff --git a/src/version.ts b/src/version.ts index ad497dc..df3ccbb 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,3 +1,3 @@ // AUTO-GENERATED by scripts/sync-version.mjs — do not edit by hand. // Sourced from package.json "version" so the two cannot drift. -export const PLUGIN_VERSION = "2.0.14"; +export const PLUGIN_VERSION = "2.0.15"; diff --git a/tui.ts b/tui.ts new file mode 100644 index 0000000..e71c754 --- /dev/null +++ b/tui.ts @@ -0,0 +1,2 @@ +// Local-development entry for the OpenCode 2 TUI companion (see server.ts). +export { default } from "./src/tui.ts"; From 2dca0b1e0c18f22a5aa0ee9d2e1a15dde784bad9 Mon Sep 17 00:00:00 2001 From: Ishaan Gupta Date: Wed, 23 Sep 2026 21:04:06 +0530 Subject: [PATCH 2/4] Add persistent Supermemory status footer for OpenCode V1 and 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #81 added the footer but was merged into graphite-base/81 instead of main, so it never shipped. Fold it into one `./tui` module that OpenCode V1 loads through tui.jsonc (`tui()`) and OpenCode 2 loads automatically next to the server plugin (`setup()`). Both show `◪ supermemory · running` while a session is busy and the latest recall or save activity otherwise; OpenCode 2 also renders the server's activity notices as toasts from the same plugin. The installer enables the V1 footer in tui.jsonc, `status` reports it, and direct-recall parts carry recall metadata so the V1 footer can read them. --- README.md | 15 +- bun.lock | 301 ++++++++++++++++++++++++++- package.json | 23 +- src/cli.ts | 42 +++- src/index.ts | 7 + src/services/opencode-config.test.ts | 15 ++ src/services/opencode-config.ts | 19 ++ src/tui-status.test.ts | 37 ++++ src/tui-status.ts | 57 +++++ src/tui.ts | 34 --- src/tui.tsx | 178 ++++++++++++++++ tsconfig.json | 2 + tui.ts | 3 +- 13 files changed, 684 insertions(+), 49 deletions(-) create mode 100644 src/tui-status.test.ts create mode 100644 src/tui-status.ts delete mode 100644 src/tui.ts create mode 100644 src/tui.tsx diff --git a/README.md b/README.md index d0d24a5..3603d42 100644 --- a/README.md +++ b/README.md @@ -194,7 +194,7 @@ On OpenCode 2, OpenCode owns the compaction trigger and model. The plugin hooks compaction request to add the same project memories, then saves each successful summary as a memory. Set `compactionEnabled: false` to opt out on OpenCode 2. -### Activity Notices +### Activity Notices and Status Footer Supermemory shows a short native notice when it recalls memories, saves a turn, falls open because recall was unavailable, or a newer release exists. Notices never enter model @@ -202,6 +202,11 @@ context. On OpenCode V1 they are TUI toasts; on OpenCode 2 they are rendered by `opencode-supermemory/tui` companion, which OpenCode loads automatically next to the server plugin. +The same TUI plugin keeps a persistent `◪ supermemory` footer. It turns blue while a +session is running and otherwise shows the latest recall or save activity. On OpenCode V1 +the installer enables it through `~/.config/opencode/tui.jsonc`; on OpenCode 2 it appears +in the prompt and home footers without extra configuration. + Set `SUPERMEMORY_DEBUG=1` to show a `[recall-decision]` line in each reply while testing advisory recall. @@ -232,7 +237,7 @@ What is the same on both generations: - First-message profile injection, keyword nudges, and automatic capture with the same cadence, privacy redaction, and idempotent capture IDs - The `supermemory` tool with identical modes, scopes, and result formatting -- Activity notices and update checks +- Activity notices, the persistent status footer, and update checks What differs on OpenCode 2: @@ -413,12 +418,18 @@ Local install (OpenCode V1 loads the built package; OpenCode 2 loads `server.ts` `tui.ts` from the checkout, so `bun install` is enough): ```jsonc +// ~/.config/opencode/opencode.jsonc { "plugin": ["file:///path/to/opencode-supermemory"], "plugins": ["/path/to/opencode-supermemory"], } ``` +The TUI side of a local checkout is registered separately: OpenCode V1 reads +`~/.config/opencode/tui.jsonc` (`"plugin": ["file:///path/to/opencode-supermemory/dist/tui.js"]`) +and OpenCode 2 reads `~/.config/opencode/cli.json` (`"plugins": ["/path/to/opencode-supermemory"]`). +Published packages need neither; both generations find the `./tui` export on their own. + `opencode plugin list` only shows package plugins, so confirm a checkout loaded by looking for `v2 plugin init` and `v2 plugin registered` in `~/.opencode-supermemory.log`. diff --git a/bun.lock b/bun.lock index 143ec47..e1c9c36 100644 --- a/bun.lock +++ b/bun.lock @@ -5,18 +5,33 @@ "": { "name": "opencode-plugin", "devDependencies": { - "@opencode-ai/plugin": "^1.0.162", + "@opencode-ai/plugin": "^1.18.20", "@opencode/plugin": "2.0.15", + "@opentui/core": "0.5.10", + "@opentui/solid": "0.5.10", "@types/bun": "latest", "jsonc-parser": "3.3.1", + "solid-js": "1.9.15", "supermemory": "^4.0.0", "typescript": "^5.7.3", }, + "peerDependencies": { + "@opentui/core": ">=0.5.8", + "@opentui/solid": ">=0.5.8", + "solid-js": ">=1.9.0", + }, + "optionalPeers": [ + "@opentui/core", + "@opentui/solid", + "solid-js", + ], }, }, "packages": { "@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="], + "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], + "@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="], "@aws-crypto/sha256-browser": ["@aws-crypto/sha256-browser@5.2.0", "", { "dependencies": { "@aws-crypto/sha256-js": "^5.2.0", "@aws-crypto/supports-web-crypto": "^5.2.0", "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-locate-window": "^3.0.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw=="], @@ -65,6 +80,62 @@ "@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.3.0", "", {}, "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ=="], + "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], + + "@babel/core": ["@babel/core@7.28.0", "", { "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.0", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.27.3", "@babel/helpers": "^7.27.6", "@babel/parser": "^7.28.0", "@babel/template": "^7.27.2", "@babel/traverse": "^7.28.0", "@babel/types": "^7.28.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ=="], + + "@babel/generator": ["@babel/generator@7.29.8", "", { "dependencies": { "@babel/parser": "^7.29.8", "@babel/types": "^7.29.8", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg=="], + + "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" } }, "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.29.7", "", { "dependencies": { "@babel/compat-data": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g=="], + + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-member-expression-to-functions": "^7.29.7", "@babel/helper-optimise-call-expression": "^7.29.7", "@babel/helper-replace-supers": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/traverse": "^7.29.7", "semver": "^6.3.1" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.29.7", "", {}, "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA=="], + + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.29.7", "", { "dependencies": { "@babel/helper-module-imports": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg=="], + + "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.29.7", "", { "dependencies": { "@babel/types": "^7.29.7" } }, "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.29.7", "", {}, "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw=="], + + "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.29.7", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "^7.29.7", "@babel/helper-optimise-call-expression": "^7.29.7", "@babel/traverse": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ=="], + + "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.29.7", "", { "dependencies": { "@babel/traverse": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.29.7", "", {}, "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw=="], + + "@babel/helpers": ["@babel/helpers@7.29.7", "", { "dependencies": { "@babel/template": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg=="], + + "@babel/parser": ["@babel/parser@7.29.9", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA=="], + + "@babel/plugin-syntax-jsx": ["@babel/plugin-syntax-jsx@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A=="], + + "@babel/plugin-syntax-typescript": ["@babel/plugin-syntax-typescript@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA=="], + + "@babel/plugin-transform-modules-commonjs": ["@babel/plugin-transform-modules-commonjs@7.29.7", "", { "dependencies": { "@babel/helper-module-transforms": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ=="], + + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.29.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/plugin-syntax-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-FFwIwzU+7SCOuxxV4YtJql6T9981ZVTm+FHO5GhVsRqCTdy0WwrEZh3l42ARpXruJUDGOptdduHW6Zr7pNPLNg=="], + + "@babel/preset-typescript": ["@babel/preset-typescript@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-validator-option": "^7.27.1", "@babel/plugin-syntax-jsx": "^7.27.1", "@babel/plugin-transform-modules-commonjs": "^7.27.1", "@babel/plugin-transform-typescript": "^7.27.1" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ=="], + + "@babel/template": ["@babel/template@7.29.7", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/parser": "^7.29.7", "@babel/types": "^7.29.7" } }, "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg=="], + + "@babel/traverse": ["@babel/traverse@7.29.8", "", { "dependencies": { "@babel/code-frame": "^7.29.7", "@babel/generator": "^7.29.8", "@babel/helper-globals": "^7.29.7", "@babel/parser": "^7.29.8", "@babel/template": "^7.29.7", "@babel/types": "^7.29.8", "debug": "^4.3.1" } }, "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg=="], + + "@babel/types": ["@babel/types@7.29.8", "", { "dependencies": { "@babel/helper-string-parser": "^7.29.7", "@babel/helper-validator-identifier": "^7.29.7" } }, "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg=="], + "@effect/opentelemetry": ["@effect/opentelemetry@4.0.0-rc.112", "", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "@opentelemetry/api-logs": ">=0.203.0 <0.300.0", "@opentelemetry/resources": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-logs": ">=0.203.0 <0.300.0", "@opentelemetry/sdk-metrics": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-base": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-node": ">=2.0.0 <3.0.0", "@opentelemetry/sdk-trace-web": ">=2.0.0 <3.0.0", "@opentelemetry/semantic-conventions": ">=1.33.0 <2.0.0", "effect": "^4.0.0-rc.112" }, "optionalPeers": ["@opentelemetry/api", "@opentelemetry/api-logs", "@opentelemetry/resources", "@opentelemetry/sdk-logs", "@opentelemetry/sdk-metrics", "@opentelemetry/sdk-trace-base", "@opentelemetry/sdk-trace-node", "@opentelemetry/sdk-trace-web"] }, "sha512-OTRv1DxTHUmnakgJ6XVM8wVgF1KgZH4UXnOemwSLUwUjXO+RCikzF8oR/rlVmOGq81KtQzj1URM4M4nchlQOuQ=="], "@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="], @@ -79,6 +150,14 @@ "@isaacs/string-locale-compare": ["@isaacs/string-locale-compare@1.1.0", "", {}, "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ=="], + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.6.0", "", {}, "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + "@msgpackr-extract/msgpackr-extract-darwin-arm64": ["@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ=="], "@msgpackr-extract/msgpackr-extract-darwin-x64": ["@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w=="], @@ -121,9 +200,9 @@ "@npmcli/run-script": ["@npmcli/run-script@10.0.4", "", { "dependencies": { "@npmcli/node-gyp": "^5.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "node-gyp": "^12.1.0", "proc-log": "^6.0.0" } }, "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg=="], - "@opencode-ai/plugin": ["@opencode-ai/plugin@1.0.191", "", { "dependencies": { "@opencode-ai/sdk": "1.0.191", "zod": "4.1.8" } }, "sha512-+Z83g4uwRM+Qed5bV/HJ9KEA4FOPEOKZgTcyIvl0lVu++VYwPXydy1+YyW+/IRp17Ghz/xF7zWL+pBh2XlT9xQ=="], + "@opencode-ai/plugin": ["@opencode-ai/plugin@1.18.32", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode-ai/sdk": "1.18.32", "effect": "4.0.0-beta.83", "zod": "4.1.8" }, "peerDependencies": { "@opentui/core": ">=0.4.5", "@opentui/keymap": ">=0.4.5", "@opentui/solid": ">=0.4.5" }, "optionalPeers": ["@opentui/core", "@opentui/keymap", "@opentui/solid"] }, "sha512-JJXaTHmkiU9EAshJOFuIkZsAuvBcLw46BAErePeER8bPeO2LL2uGyBRt4tuLJjJ2N7v1vlZgfvAD7bWKupke1A=="], - "@opencode-ai/sdk": ["@opencode-ai/sdk@1.0.191", "", {}, "sha512-UjbwaxdrP8XFbMcCCy4FfWbGrY1Kz/6wzdg34ASCVlXA/FxfWw7cFhM9oPKnwmR7HyGY7nq/y4Ywb0yW9TAwEA=="], + "@opencode-ai/sdk": ["@opencode-ai/sdk@1.18.32", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-Wi3WtH/cLA3C0ga05lyDb7zac+SzbST9MPwCve1Ffod0xwzHdy9G2gnxvMAR4RBRhKJS32Rgk2cR+fxBhAVSQw=="], "@opencode/ai": ["@opencode/ai@2.0.15", "", { "dependencies": { "@aws-sdk/credential-providers": "3.1057.0", "@opencode/schema": "2.0.15", "@smithy/eventstream-codec": "4.2.14", "@smithy/util-utf8": "4.2.2", "aws4fetch": "1.0.20", "effect": "4.0.0-rc.112", "google-auth-library": "10.5.0" } }, "sha512-dY3HG6bp+UMJOi+m1nfzvQaTPpCSmMNDswAOLQq/MJghGrD54WrcEC4IhAQ1hJY7b/hhQYOzPAMeJsvF4aRYYQ=="], @@ -163,6 +242,26 @@ "@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.43.0", "", {}, "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg=="], + "@opentui/core": ["@opentui/core@0.5.10", "", { "dependencies": { "bun-ffi-structs": "0.3.1", "diff": "9.0.0", "marked": "17.0.1", "string-width": "7.2.0", "strip-ansi": "7.1.2" }, "optionalDependencies": { "@opentui/core-darwin-arm64": "0.5.10", "@opentui/core-darwin-x64": "0.5.10", "@opentui/core-linux-arm64": "0.5.10", "@opentui/core-linux-arm64-musl": "0.5.10", "@opentui/core-linux-x64": "0.5.10", "@opentui/core-linux-x64-musl": "0.5.10", "@opentui/core-win32-arm64": "0.5.10", "@opentui/core-win32-x64": "0.5.10" }, "peerDependencies": { "web-tree-sitter": "0.25.10" } }, "sha512-C3a2UbmefeAjIxAgm4BqjuSxKT4oqutfvYFwVvUgMxmGRHkNbBc/s7sukV0JgwcxFcV3uMFrXxo+E+BQtvuOiw=="], + + "@opentui/core-darwin-arm64": ["@opentui/core-darwin-arm64@0.5.10", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Vyb+nTbhab8ZcRy5gg1loEEGwRcIbjAeVRIBfHBcbFDqmITBOg7x2gqJ+x/TnoOy4uwMhCmICUN2wiyREw3r1Q=="], + + "@opentui/core-darwin-x64": ["@opentui/core-darwin-x64@0.5.10", "", { "os": "darwin", "cpu": "x64" }, "sha512-tTFLcM7Oj1gTyhm/bUdAt3C6grZdCxPk6+/g2azcZBUlI3/62LwbeRS6HbQKFFmm+1fUmX8cq6kWrtul885mVg=="], + + "@opentui/core-linux-arm64": ["@opentui/core-linux-arm64@0.5.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-ncJXcgudhBf2GdJyF3xVQN/Ec+1F7GOL+pRrURmgBYSj2v1w6EyoDQFAACtPTK2c3R38W6fvZwL4JSLlm4EFXQ=="], + + "@opentui/core-linux-arm64-musl": ["@opentui/core-linux-arm64-musl@0.5.10", "", { "os": "linux", "cpu": "arm64" }, "sha512-dGMphDKexSdeYqwl0wgoFBP88Ta/cdi1Zc1mk29/ENkSCGz+74zlCHgqTHRNGLmI8W5TfuUtCyktQH11/Z+TBQ=="], + + "@opentui/core-linux-x64": ["@opentui/core-linux-x64@0.5.10", "", { "os": "linux", "cpu": "x64" }, "sha512-5qtYaOgwVycZD1GaGshTRsi0rXPAmVExO03N1JQaHu+NYxK/vXSOc7Bu4QW0sPXx3Sp0SpzpP+FHjXABfoK66g=="], + + "@opentui/core-linux-x64-musl": ["@opentui/core-linux-x64-musl@0.5.10", "", { "os": "linux", "cpu": "x64" }, "sha512-Oj4H9hApuvuTKPWxh4SoZAgGJorR7vbvnrZA/cAkSMAk2VGSoHRRcqeXQbcH8IcdjVZ0KFpv8Zkl/D5Ye+2mew=="], + + "@opentui/core-win32-arm64": ["@opentui/core-win32-arm64@0.5.10", "", { "os": "win32", "cpu": "arm64" }, "sha512-A9VhgvTxQoUdZ+8LmUumEng1sQNbj9QQQT3NYG9mSxI54qTANi7vOWNSphMiY6RMVsr22pgm6nUvSSvJXv7Jog=="], + + "@opentui/core-win32-x64": ["@opentui/core-win32-x64@0.5.10", "", { "os": "win32", "cpu": "x64" }, "sha512-u3KHa7kEeWrmKVDRJYpxSGO+g5E9cMGlrmTsPN3GVPHUmQMiREUawLXUvsU8+IHaQnqG3Q5nuE1yf4fPBzS+Qw=="], + + "@opentui/solid": ["@opentui/solid@0.5.10", "", { "dependencies": { "@babel/core": "7.28.0", "@babel/preset-typescript": "7.27.1", "@opentui/core": "0.5.10", "babel-plugin-module-resolver": "5.0.2", "babel-preset-solid": "1.9.12", "entities": "7.0.1", "s-js": "^0.4.9" }, "peerDependencies": { "solid-js": "1.9.12" } }, "sha512-KrmMIsHiKBHOABTC0brOwqWm+sGq1ZX2sGCAx6WgtBbE3STMup9n8TAy/6gUYhwcjC9zugT53ytfSVwCwVWZUg=="], + "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], "@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="], @@ -249,10 +348,18 @@ "aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="], + "babel-plugin-jsx-dom-expressions": ["babel-plugin-jsx-dom-expressions@0.40.10", "", { "dependencies": { "@babel/helper-module-imports": "7.18.6", "@babel/plugin-syntax-jsx": "^7.18.6", "@babel/types": "^7.20.7", "html-entities": "2.3.3", "parse5": "^7.1.2" }, "peerDependencies": { "@babel/core": "^7.20.12" } }, "sha512-lxve6Y02YiZTldB7efKpnbf1BH00XCFZNYYW235jSGsYaJNFtHrYlKV6/O+miHbjqpIr9FTe5+0no4hofAMbfA=="], + + "babel-plugin-module-resolver": ["babel-plugin-module-resolver@5.0.2", "", { "dependencies": { "find-babel-config": "^2.1.1", "glob": "^9.3.3", "pkg-up": "^3.1.0", "reselect": "^4.1.7", "resolve": "^1.22.8" } }, "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg=="], + + "babel-preset-solid": ["babel-preset-solid@1.9.12", "", { "dependencies": { "babel-plugin-jsx-dom-expressions": "^0.40.6" }, "peerDependencies": { "@babel/core": "^7.0.0", "solid-js": "^1.9.12" }, "optionalPeers": ["solid-js"] }, "sha512-LLqnuKVDlKpyBlMPcH6qEvs/wmS9a+NczppxJ3ryS/c0O5IiSFOIBQi9GzyiGDSbcJpx4Gr87jyFTos1MyEuWg=="], + "balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.11.25", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw=="], + "bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="], "bin-links": ["bin-links@6.0.2", "", { "dependencies": { "cmd-shim": "^8.0.0", "npm-normalize-package-bin": "^5.0.0", "proc-log": "^6.0.0", "read-cmd-shim": "^6.0.0", "write-file-atomic": "^7.0.0" } }, "sha512-frE1t78WOwJ45PKV2cF2tNPjTcs9L1J9s6VkrV59wanRP4GlaomuxYPVma7BwthMg8WnfSory4w5PTE6FZZ81w=="], @@ -261,12 +368,18 @@ "brace-expansion": ["brace-expansion@5.0.12", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ=="], + "browserslist": ["browserslist@4.29.0", "", { "dependencies": { "baseline-browser-mapping": "^2.11.23", "caniuse-lite": "^1.0.30001810", "electron-to-chromium": "^1.5.427", "node-releases": "^2.0.55", "update-browserslist-db": "^1.3.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA=="], + "buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="], + "bun-ffi-structs": ["bun-ffi-structs@0.3.1", "", { "peerDependencies": { "typescript": "^5" } }, "sha512-3gM7PpVWLyrwxWjcilSiGuhWanhZivvo6l0u573NziPH6f/gwk6McbaYgn7oJWov6pKGRTDbrg94W5DcJsKTtQ=="], + "bun-types": ["bun-types@1.3.5", "", { "dependencies": { "@types/node": "*" } }, "sha512-inmAYe2PFLs0SUbFOWSVD24sg1jFlMPxOjOSSCYqUgn4Hsc3rDc7dFvfVYjFPNHtov6kgUeulV4SxbuIV/stPw=="], "cacache": ["cacache@20.0.4", "", { "dependencies": { "@npmcli/fs": "^5.0.0", "fs-minipass": "^3.0.0", "glob": "^13.0.0", "lru-cache": "^11.1.0", "minipass": "^7.0.3", "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^7.0.2", "ssri": "^13.0.0" } }, "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA=="], + "caniuse-lite": ["caniuse-lite@1.0.30001810", "", {}, "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg=="], + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], @@ -283,26 +396,40 @@ "content-type": ["content-type@2.1.0", "", {}, "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + "data-uri-to-buffer": ["data-uri-to-buffer@4.0.1", "", {}, "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" }, "peerDependencies": { "supports-color": "*" }, "optionalPeers": ["supports-color"] }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + "diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], "ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "^5.0.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="], - "effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + "effect": ["effect@4.0.0-beta.83", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.8.0", "find-my-way-ts": "^0.1.6", "ini": "^7.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^2.0.1", "multipasta": "^0.2.7", "toml": "^4.1.1", "uuid": "^14.0.0", "yaml": "^2.9.0" } }, "sha512-0wsak8RtgGAr9UWSbVDgJHZcUqMSvicHcvaZv1MbMM7MCGgW4Rn/137J1MHQbwYPcwYGxT/IqehFd+UbYuj78w=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.438", "", {}, "sha512-AN9xMU1hJiT65LkCUPL1DZm5TCbOPb2Qsm5pYwFLEXp6/qj9SdT4yMiqs7Qqstwvkn1zF7l36SRGt+s6XcJ0FA=="], + + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], - "emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], @@ -313,16 +440,30 @@ "fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "^1.0.0", "web-streams-polyfill": "^3.0.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="], + "find-babel-config": ["find-babel-config@2.1.2", "", { "dependencies": { "json5": "^2.2.3" } }, "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg=="], + + "find-my-way-ts": ["find-my-way-ts@0.1.6", "", {}, "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA=="], + + "find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "^3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], + "foreground-child": ["foreground-child@3.3.1", "", { "dependencies": { "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" } }, "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw=="], "formdata-polyfill": ["formdata-polyfill@4.0.10", "", { "dependencies": { "fetch-blob": "^3.1.2" } }, "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g=="], "fs-minipass": ["fs-minipass@3.0.3", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw=="], + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "gaxios": ["gaxios@7.3.1", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ=="], "gcp-metadata": ["gcp-metadata@8.1.4", "", { "dependencies": { "gaxios": "7.1.3", "google-logging-utils": "1.1.3", "json-bigint": "^1.0.0" } }, "sha512-iJ9KMsiu+xKtNRX0PmGLSaIU3bUBAyzWTyqKemKPzNPsmmsBCQYmlNg+brEbES7IHSXtdVwzBPzx1vz3FAaipw=="], + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-east-asian-width": ["get-east-asian-width@1.7.0", "", {}, "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q=="], + "glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], "google-auth-library": ["google-auth-library@10.5.0", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.0.0", "gcp-metadata": "^8.0.0", "google-logging-utils": "^1.0.0", "gtoken": "^8.0.0", "jws": "^4.0.0" } }, "sha512-7ABviyMOlX5hIVD60YOfHw4/CxOfBhyduaYB+wbFWCWoni4N7SLcV46hrVRktuBbZjFC9ONyqamZITN7q3n32w=="], @@ -333,8 +474,12 @@ "gtoken": ["gtoken@8.0.0", "", { "dependencies": { "gaxios": "^7.0.0", "jws": "^4.0.0" } }, "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw=="], + "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], + "hosted-git-info": ["hosted-git-info@9.0.3", "", { "dependencies": { "lru-cache": "^11.1.0" } }, "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg=="], + "html-entities": ["html-entities@2.3.3", "", {}, "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA=="], + "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], @@ -345,16 +490,22 @@ "ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="], - "ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], + "ini": ["ini@7.0.0", "", {}, "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w=="], "ip-address": ["ip-address@10.7.2", "", {}, "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w=="], + "is-core-module": ["is-core-module@2.17.0", "", { "dependencies": { "hasown": "^2.0.4" } }, "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA=="], + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + "json-bigint": ["json-bigint@1.0.0", "", { "dependencies": { "bignumber.js": "^9.0.0" } }, "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ=="], "json-parse-even-better-errors": ["json-parse-even-better-errors@5.0.0", "", {}, "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ=="], @@ -363,6 +514,8 @@ "json-stringify-nice": ["json-stringify-nice@1.1.4", "", {}, "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw=="], + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], "jsonparse": ["jsonparse@1.3.1", "", {}, "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg=="], @@ -375,12 +528,18 @@ "jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="], + "kubernetes-types": ["kubernetes-types@1.30.0", "", {}, "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q=="], + + "locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], + "long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="], "lru-cache": ["lru-cache@11.5.3", "", {}, "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg=="], "make-fetch-happen": ["make-fetch-happen@15.0.6", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/agent": "^4.0.0", "@npmcli/redact": "^4.0.0", "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^1.0.0", "proc-log": "^6.0.0", "ssri": "^13.0.0" } }, "sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw=="], + "marked": ["marked@17.0.1", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg=="], + "mime": ["mime@4.1.0", "", { "bin": { "mime": "bin/cli.js" } }, "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw=="], "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], @@ -409,6 +568,8 @@ "msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], + "multipasta": ["multipasta@0.2.8", "", {}, "sha512-ZPWuMKyv0cSO29f7hozp+k6+crZbQijV8ipMvxNxRf2SwtYGTX1ZX89Kd20VV4H9Znonx+EQn+iy1wGQsJ+b+Q=="], + "negotiator": ["negotiator@1.1.0", "", { "dependencies": { "content-type": "^2.1.0" } }, "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg=="], "node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="], @@ -419,6 +580,8 @@ "node-gyp-build-optional-packages": ["node-gyp-build-optional-packages@5.2.2", "", { "dependencies": { "detect-libc": "^2.0.1" }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", "node-gyp-build-optional-packages-test": "build-test.js" } }, "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw=="], + "node-releases": ["node-releases@2.0.57", "", {}, "sha512-kQK9LGGFiHtrWiNhZtA7Qbw17AQz+dmsEKODRIVTXA9+e5MS/2gZEBhYJt13GrAz5/IOZKddH/0Z3TP/Zgo+yw=="], + "nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], "npm-bundled": ["npm-bundled@5.0.0", "", { "dependencies": { "npm-normalize-package-bin": "^5.0.0" } }, "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw=="], @@ -435,20 +598,36 @@ "npm-registry-fetch": ["npm-registry-fetch@19.1.1", "", { "dependencies": { "@npmcli/redact": "^4.0.0", "jsonparse": "^1.3.1", "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", "minipass-fetch": "^5.0.0", "minizlib": "^3.0.1", "npm-package-arg": "^13.0.0", "proc-log": "^6.0.0" } }, "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw=="], + "p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "^2.0.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "^2.0.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], + "p-map": ["p-map@7.0.8", "", {}, "sha512-MitaVsCuCFIvOLLPIU7NnfrZvS9H9h7kwMUkDo+T2pEISaJD48IV9S8iIdXB7PsvvdxyYcsSTTrr90XKsbulNw=="], + "p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + "package-json-from-dist": ["package-json-from-dist@1.0.1", "", {}, "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="], "pacote": ["pacote@21.5.1", "", { "dependencies": { "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", "@npmcli/promise-spawn": "^9.0.0", "@npmcli/run-script": "^10.0.0", "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", "npm-package-arg": "^13.0.0", "npm-packlist": "^10.0.1", "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" }, "bin": { "pacote": "bin/index.js" } }, "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg=="], "parse-conflict-json": ["parse-conflict-json@5.0.1", "", { "dependencies": { "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" } }, "sha512-ZHEmNKMq1wyJXNwLxyHnluPfRAFSIliBvbK/UiOceROt4Xh9Pz0fq49NytIaeaCUf5VR86hwQ/34FCcNU5/LKQ=="], + "parse5": ["parse5@7.3.0", "", { "dependencies": { "entities": "^6.0.0" } }, "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw=="], + + "path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + "path-scurry": ["path-scurry@2.0.2", "", { "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" } }, "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + "picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="], + "pkg-up": ["pkg-up@3.1.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="], + "postcss-selector-parser": ["postcss-selector-parser@7.1.6", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw=="], "proc-log": ["proc-log@6.1.0", "", {}, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="], @@ -467,13 +646,23 @@ "redis": ["redis@6.2.1", "", { "dependencies": { "@redis/bloom": "6.2.1", "@redis/client": "6.2.1", "@redis/json": "6.2.1", "@redis/search": "6.2.1", "@redis/time-series": "6.2.1" } }, "sha512-Z9VHtgYs48PiQC77X9O2Er8Hj4T+5BtFjT91/vi5Is1D04N72cA946ZslM1ImJw8ZctFBZWAVjM7S5wJNeHMpg=="], + "reselect": ["reselect@4.1.8", "", {}, "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ=="], + + "resolve": ["resolve@1.22.12", "", { "dependencies": { "es-errors": "^1.3.0", "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA=="], + "rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "^10.3.7" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="], + "s-js": ["s-js@0.4.9", "", {}, "sha512-RtpOm+cM6O0sHg6IA70wH+UC3FZcND+rccBZpBAHzlUgNO2Bm5BN+FnM8+OBxzXdwpKWFwX11JGF0MFRkhSoIQ=="], + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "seroval": ["seroval@1.5.6", "", {}, "sha512-rVQVWjjSvlINzaQPZH5JFqsqEsIWdTxY3iJZCnTL/5gQbXIRooVZKI60tVCkOVfzcRPejboxO2t0P89dg5mQaA=="], + + "seroval-plugins": ["seroval-plugins@1.5.6", "", { "peerDependencies": { "seroval": "^1.0" } }, "sha512-HXuLAX2pu/UByPpaeo/TaMfvMIi+1QqIoPJYCcAtU8QkVNwgR6MPlGuCQTErV1JwraaMbYaWVIBX7mppzGLATQ=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -489,6 +678,8 @@ "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "socks": "^2.8.3" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + "solid-js": ["solid-js@1.9.15", "", { "dependencies": { "csstype": "^3.1.0", "seroval": "~1.5.4", "seroval-plugins": "~1.5.4" } }, "sha512-EeiY2xfpZJqPLjXspVEKjAII4yv8NyG//NxZ3IpOFHdUNnnTyL0uJOeS9LWGvA7cFCz5y94cjFwYlmw5Luncsg=="], + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], "spdx-expression-parse": ["spdx-expression-parse@4.0.0", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ=="], @@ -497,20 +688,24 @@ "ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="], - "string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], "string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], - "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + "strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], "strip-ansi-cjs": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "supermemory": ["supermemory@4.0.0", "", {}, "sha512-xMN05PQ8kTv8DuXa2qf8h/9LaRI7v1Kz3Tutt97JPq+PzhGabKLv5YVbSgqHiPX5yXcSUBVBNYPPbhAQMF6GYQ=="], + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + "tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="], "tinyglobby": ["tinyglobby@0.2.17", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g=="], + "toml": ["toml@4.3.0", "", {}, "sha512-lVb8X9BsPVuH0M4BKeS91tXAmJvCjQ5UIyAbQFaxkKGyUFK2RPkhwaFSQH8vbpl1d23eu/IBH+dwVMHWaq9A5A=="], + "treeverse": ["treeverse@3.0.0", "", {}, "sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -523,14 +718,20 @@ "undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + "update-browserslist-db": ["update-browserslist-db@1.3.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "uuid": ["uuid@14.0.2", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ=="], + "validate-npm-package-name": ["validate-npm-package-name@7.0.2", "", {}, "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A=="], "walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="], "web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="], + "web-tree-sitter": ["web-tree-sitter@0.25.10", "", { "peerDependencies": { "@types/emscripten": "^1.40.0" }, "optionalPeers": ["@types/emscripten"] }, "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA=="], + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], @@ -543,16 +744,62 @@ "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + "yaml": ["yaml@2.9.1", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw=="], + "zod": ["zod@4.1.8", "", {}, "sha512-5R1P+WwQqmmMIEACyzSvo4JXHY5WiAFHRMg+zBZKgKS+Q1viRa0C1hmUKtHltoIFKtIdki3pRxkmpP74jnNYHQ=="], "@aws-crypto/sha256-browser/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], "@aws-crypto/util/@smithy/util-utf8": ["@smithy/util-utf8@2.3.0", "", { "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A=="], + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "@effect/opentelemetry/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "@effect/platform-node/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "@effect/platform-node-shared/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "@isaacs/cliui/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "@isaacs/cliui/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + + "@npmcli/arborist/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "@npmcli/config/ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], + + "@npmcli/config/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "@npmcli/fs/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "@npmcli/git/ini": ["ini@6.0.0", "", {}, "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ=="], + + "@npmcli/git/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "@npmcli/git/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + "@npmcli/metavuln-calculator/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "@npmcli/package-json/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "@npmcli/promise-spawn/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + "@opencode/ai/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "@opencode/client/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "@opencode/plugin/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "@opencode/protocol/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "@opencode/schema/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "@opencode/util/effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], + + "babel-plugin-jsx-dom-expressions/@babel/helper-module-imports": ["@babel/helper-module-imports@7.18.6", "", { "dependencies": { "@babel/types": "^7.18.6" } }, "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA=="], + + "babel-plugin-module-resolver/glob": ["glob@9.3.5", "", { "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^8.0.2", "minipass": "^4.2.4", "path-scurry": "^1.6.1" } }, "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q=="], + "gcp-metadata/gaxios": ["gaxios@7.1.3", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2", "rimraf": "^5.0.1" } }, "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ=="], "gcp-metadata/google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], @@ -561,18 +808,34 @@ "minipass-pipeline/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="], + "node-gyp/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + "node-gyp/undici": ["undici@6.28.1", "", {}, "sha512-zWpdTVD54H48CIybL0rWQ3ukpb9d23wM7eH5RtfdmeP70cWHNjtfo7P4vZX+5CoDcO53J4Pu5uXp7lNfjc6DRA=="], "node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + "npm-install-checks/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "npm-package-arg/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "npm-pick-manifest/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + "rimraf/glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], + "string-width/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + "string-width-cjs/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], "string-width-cjs/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "strip-ansi-cjs/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", "strip-ansi": "^7.0.1" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "wrap-ansi/strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + "wrap-ansi-cjs/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], "wrap-ansi-cjs/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], @@ -583,10 +846,20 @@ "@aws-crypto/util/@smithy/util-utf8/@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="], + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "@isaacs/cliui/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + "@npmcli/git/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], "@npmcli/promise-spawn/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + "babel-plugin-module-resolver/glob/minimatch": ["minimatch@8.0.7", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg=="], + + "babel-plugin-module-resolver/glob/minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], + + "babel-plugin-module-resolver/glob/path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + "minipass-flush/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], "minipass-pipeline/minipass/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], @@ -603,10 +876,20 @@ "wrap-ansi-cjs/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "wrap-ansi/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "babel-plugin-module-resolver/glob/minimatch/brace-expansion": ["brace-expansion@2.1.7", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g=="], + + "babel-plugin-module-resolver/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "babel-plugin-module-resolver/glob/path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.1.7", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g=="], "rimraf/glob/path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + "babel-plugin-module-resolver/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + "rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], } } diff --git a/package.json b/package.json index 3465502..270fe74 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ }, "scripts": { "generate:version": "node scripts/sync-version.mjs", - "build": "node scripts/sync-version.mjs && bun build ./src/index.ts ./src/server.ts ./src/tui.ts ./src/rpc.ts --outdir ./dist --target node && bun build ./src/v2/index.ts --outfile ./dist/v2/index.js --target node && bun build ./src/cli.ts --outfile ./dist/cli.js --target node && tsc --emitDeclarationOnly", + "build": "node scripts/sync-version.mjs && bun build ./src/index.ts ./src/server.ts ./src/rpc.ts --outdir ./dist --target node && bun build ./src/tui.tsx --outfile ./dist/tui.js --target bun --external @opentui/core --external @opentui/solid --external solid-js && bun build ./src/v2/index.ts --outfile ./dist/v2/index.js --target node && bun build ./src/cli.ts --outfile ./dist/cli.js --target node && tsc --emitDeclarationOnly", "dev": "tsc --watch", "typecheck": "node scripts/sync-version.mjs && tsc --noEmit", "test": "node scripts/sync-version.mjs && bun test" @@ -60,13 +60,32 @@ "url": "https://github.com/supermemoryai/opencode-supermemory" }, "devDependencies": { - "@opencode-ai/plugin": "^1.0.162", + "@opencode-ai/plugin": "^1.18.20", "@opencode/plugin": "2.0.15", + "@opentui/core": "0.5.10", + "@opentui/solid": "0.5.10", "@types/bun": "latest", "jsonc-parser": "3.3.1", + "solid-js": "1.9.15", "supermemory": "^4.0.0", "typescript": "^5.7.3" }, + "peerDependencies": { + "@opentui/core": ">=0.5.8", + "@opentui/solid": ">=0.5.8", + "solid-js": ">=1.9.0" + }, + "peerDependenciesMeta": { + "@opentui/core": { + "optional": true + }, + "@opentui/solid": { + "optional": true + }, + "solid-js": { + "optional": true + } + }, "opencode": { "type": "plugin", "hooks": [ diff --git a/src/cli.ts b/src/cli.ts index 92871ae..686c7d5 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -9,7 +9,9 @@ import { SupermemoryClient } from "./services/client.js"; import { getTags } from "./services/tags.js"; import { editOpenCodeConfig, + editOpenCodeTuiConfig, readOpenCodeRegistration, + readOpenCodeTuiRegistration, V1_PLUGIN_ENTRY, V2_PLUGIN_ENTRY, } from "./services/opencode-config.js"; @@ -19,6 +21,10 @@ const OPENCODE_COMMAND_DIRS = [ join(OPENCODE_CONFIG_DIR, "commands"), join(OPENCODE_CONFIG_DIR, "command"), ]; +const OPENCODE_TUI_CONFIGS = [ + join(OPENCODE_CONFIG_DIR, "tui.jsonc"), + join(OPENCODE_CONFIG_DIR, "tui.json"), +]; const OH_MY_OPENCODE_CONFIG = join(OPENCODE_CONFIG_DIR, "oh-my-opencode.json"); const DEFAULT_CONFIG_FILE = CONFIG_FILE ?? join(OPENCODE_CONFIG_DIR, "supermemory.json"); @@ -308,6 +314,26 @@ function createNewConfig(): boolean { return true; } +function configureTuiPlugin(): boolean { + const configPath = OPENCODE_TUI_CONFIGS.find((path) => existsSync(path)) ?? OPENCODE_TUI_CONFIGS[0]!; + try { + const content = existsSync(configPath) ? readFileSync(configPath, "utf-8") : ""; + const result = editOpenCodeTuiConfig(content); + if (result.changed) { + mkdirSync(OPENCODE_CONFIG_DIR, { recursive: true }); + writeFileSync(configPath, result.content); + console.log(`✓ Enabled the persistent Supermemory footer for OpenCode V1 in ${configPath}`); + } else { + console.log("✓ Persistent Supermemory footer already enabled for OpenCode V1"); + } + console.log(" OpenCode 2 loads the footer automatically from the plugin package."); + return true; + } catch (err) { + console.error("✗ Failed to update TUI config:", err); + return false; + } +} + function createCommands(): boolean { const files: Array<[string, string]> = [ ["supermemory-index.md", SUPERMEMORY_INDEX_COMMAND], @@ -422,6 +448,8 @@ async function install(options: InstallOptions): Promise { } } + configureTuiPlugin(); + // Step 2: Create commands console.log("\nStep 2: Create /supermemory-index, /supermemory-init, /supermemory-login, /supermemory-logout, and /supermemory-status commands"); if (options.tui) { @@ -571,10 +599,22 @@ function describeOpenCodeRegistration(): string[] { : registration.recallAllowed ? "recall auto-allowed" : "default permissions"; + const tuiConfig = OPENCODE_TUI_CONFIGS.find((path) => existsSync(path)); + let tuiFooter = "missing (re-run install)"; + if (tuiConfig) { + try { + if (readOpenCodeTuiRegistration(readFileSync(tuiConfig, "utf-8"))) { + tuiFooter = `registered (${tuiConfig})`; + } + } catch { + tuiFooter = `unreadable (${tuiConfig})`; + } + } return [ `OpenCode config: ${configPath}`, `OpenCode V1 plugin entry: ${registration.v1 ? "registered" : `missing (add \"${V1_PLUGIN_ENTRY}\" to \"plugin\")`}`, - `OpenCode 2 plugin entry: ${registration.v2 ? `registered (${v2Permission})` : `missing (add \"${V2_PLUGIN_ENTRY}\" to \"plugins\")`}`, + `OpenCode V1 TUI footer: ${tuiFooter}`, + `OpenCode 2 plugin entry: ${registration.v2 ? `registered (${v2Permission}; footer loads automatically)` : `missing (add \"${V2_PLUGIN_ENTRY}\" to \"plugins\")`}`, ]; } catch (error) { return [`OpenCode config: ${configPath} (unreadable: ${error instanceof Error ? error.message : String(error)})`]; diff --git a/src/index.ts b/src/index.ts index f1f640e..b062239 100644 --- a/src/index.ts +++ b/src/index.ts @@ -275,6 +275,13 @@ export const SupermemoryPlugin: Plugin = async (ctx: PluginInput) => { type: "text", text: directRecall.context, synthetic: true, + metadata: { + supermemory: { + activity: "recalled", + count: directRecall.count, + tokens: directRecall.tokens, + }, + }, }); } diff --git a/src/services/opencode-config.test.ts b/src/services/opencode-config.test.ts index 1590197..79b1a48 100644 --- a/src/services/opencode-config.test.ts +++ b/src/services/opencode-config.test.ts @@ -2,7 +2,9 @@ import { describe, expect, test } from "bun:test"; import { editOpenCodeConfig, + editOpenCodeTuiConfig, readOpenCodeRegistration, + readOpenCodeTuiRegistration, RECALL_PERMISSION, V1_PLUGIN_ENTRY, V2_PLUGIN_ENTRY, @@ -74,3 +76,16 @@ describe("OpenCode config editor", () => { ); }); }); + +describe("OpenCode V1 TUI config editor", () => { + test("adds the package to tui.jsonc once and recognises local builds", () => { + const first = editOpenCodeTuiConfig(""); + expect(JSON.parse(first.content)).toEqual({ plugin: [V1_PLUGIN_ENTRY] }); + expect(editOpenCodeTuiConfig(first.content).changed).toBe(false); + + const local = '{\n "plugin": ["file:///Users/me/opencode-supermemory/dist/tui.js"]\n}\n'; + expect(editOpenCodeTuiConfig(local).changed).toBe(false); + expect(readOpenCodeTuiRegistration(local)).toBe(true); + expect(readOpenCodeTuiRegistration('{"plugin": ["other"]}')).toBe(false); + }); +}); diff --git a/src/services/opencode-config.ts b/src/services/opencode-config.ts index 056dadf..c486259 100644 --- a/src/services/opencode-config.ts +++ b/src/services/opencode-config.ts @@ -33,6 +33,25 @@ export interface OpenCodeRegistration { recallDenied: boolean; } +/** + * OpenCode V1 loads TUI plugins from the `plugin` array of `tui.jsonc`. Adds + * the package there so the persistent footer appears; OpenCode 2 finds the + * `./tui` export on its own. + */ +export function editOpenCodeTuiConfig(rawContent: string): OpenCodeConfigEditResult { + const original = rawContent; + let content = rawContent.trim() === "" ? "{}\n" : rawContent; + parseOpenCodeConfig(content); + content = addArrayEntry(content, "plugin", V1_PLUGIN_ENTRY, isSupermemoryPluginEntry); + return { content, changed: content !== original, warnings: [] }; +} + +export function readOpenCodeTuiRegistration(content: string): boolean { + const config = parseOpenCodeConfig(content); + const plugin = Array.isArray(config.plugin) ? config.plugin : []; + return plugin.some(isSupermemoryPluginEntry); +} + type JsonObject = Record; function isObject(value: unknown): value is JsonObject { diff --git a/src/tui-status.test.ts b/src/tui-status.test.ts new file mode 100644 index 0000000..72d2262 --- /dev/null +++ b/src/tui-status.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, test } from "bun:test"; + +import { + activityLabel, + getRecallActivity, + recallLabel, + STATUS_PREFIX, + statusText, +} from "./tui-status.js"; + +describe("status footer helpers", () => { + test("reads recall activity from metadata or recalled context text", () => { + expect( + getRecallActivity({ + type: "text", + text: "", + metadata: { supermemory: { activity: "recalled", count: 2, tokens: 90 } }, + }), + ).toEqual({ count: 2, tokens: 90 }); + + const text = ["", "- ◪ one", "- ◪ two", "- ◪ three", ""].join("\n"); + expect(getRecallActivity({ type: "text", text })).toEqual({ + count: 3, + tokens: Math.round(text.length / 4), + }); + expect(getRecallActivity({ type: "tool", text })).toBeNull(); + expect(getRecallActivity({ type: "text", text: "plain" })).toBeNull(); + }); + + test("formats footer text", () => { + expect(recallLabel({ count: 1, tokens: 40 })).toBe("recalled 1 memory (40 tok)"); + expect(activityLabel(`${STATUS_PREFIX}saved this turn`)).toBe("saved this turn"); + expect(activityLabel("other")).toBe("other"); + expect(statusText(true, "saved this turn")).toBe(`${STATUS_PREFIX}running`); + expect(statusText(false, "saved this turn")).toBe(`${STATUS_PREFIX}saved this turn`); + }); +}); diff --git a/src/tui-status.ts b/src/tui-status.ts new file mode 100644 index 0000000..4132598 --- /dev/null +++ b/src/tui-status.ts @@ -0,0 +1,57 @@ +/** + * Pure helpers for the persistent `◪ supermemory` footer shared by the OpenCode + * V1 and OpenCode 2 TUI plugins. Kept free of JSX so they can be unit tested. + */ +export const STATUS_PREFIX = "◪ supermemory · "; +export const DEFAULT_STATUS_ACTIVITY = "ready"; + +export interface RecallActivity { + count: number; + tokens: number; +} + +function asRecord(value: unknown): Record | null { + return value && typeof value === "object" + ? (value as Record) + : null; +} + +/** + * Reads recall activity from an OpenCode V1 message part: either the metadata + * the server plugin attaches to direct-recall parts, or the recalled context + * text itself for older plugin builds. + */ +export function getRecallActivity(part: unknown): RecallActivity | null { + const value = asRecord(part); + if (!value || value.type !== "text") return null; + + const metadata = asRecord(value.metadata); + const supermemory = asRecord(metadata?.supermemory); + if (supermemory?.activity === "recalled") { + const count = supermemory.count; + const tokens = supermemory.tokens; + if (typeof count === "number" && typeof tokens === "number") { + return { count, tokens }; + } + } + + const text = typeof value.text === "string" ? value.text : ""; + if (!text.includes("")) return null; + const count = text.split("\n").filter((line) => line.startsWith("- ◪ ")).length; + return count > 0 ? { count, tokens: Math.round(text.length / 4) } : null; +} + +export function recallLabel(activity: RecallActivity): string { + return `recalled ${activity.count} ${activity.count === 1 ? "memory" : "memories"} (${activity.tokens} tok)`; +} + +/** Strips the shared notice prefix so the footer shows only the activity. */ +export function activityLabel(message: string): string { + return message.startsWith(STATUS_PREFIX) + ? message.slice(STATUS_PREFIX.length) + : message; +} + +export function statusText(running: boolean, activity: string): string { + return `${STATUS_PREFIX}${running ? "running" : activity}`; +} diff --git a/src/tui.ts b/src/tui.ts deleted file mode 100644 index 3f079d9..0000000 --- a/src/tui.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * OpenCode 2 TUI companion. OpenCode resolves `opencode-supermemory/tui` - * automatically next to the server entry and runs it inside the terminal UI. - * It only renders activity notices emitted by the server plugin as toasts. - */ -import type { Plugin as TuiPlugin } from "@opencode/plugin/tui"; - -type Context = TuiPlugin.Context; -type Definition = TuiPlugin.Definition; - -import { - isSupermemoryActivityEvent, - SUPERMEMORY_ACTIVITY_EVENT, -} from "./rpc.js"; - -const plugin: Definition = { - id: "supermemory.tui", - setup(context: Context) { - const stop = context.data.listen(({ details }) => { - if (details.type !== SUPERMEMORY_ACTIVITY_EVENT) return; - const data = (details as { data?: unknown }).data; - if (!isSupermemoryActivityEvent(data)) return; - context.ui.toast.show({ - title: data.title, - message: data.message, - variant: data.variant, - duration: data.duration, - }); - }); - return () => stop(); - }, -}; - -export default plugin; diff --git a/src/tui.tsx b/src/tui.tsx new file mode 100644 index 0000000..c45339d --- /dev/null +++ b/src/tui.tsx @@ -0,0 +1,178 @@ +/** @jsxImportSource @opentui/solid */ +/** + * TUI plugin for both OpenCode generations, resolved as `opencode-supermemory/tui`. + * + * OpenCode V1 calls `tui()` (registered through `~/.config/opencode/tui.jsonc`); + * OpenCode 2 calls `setup()` (loaded automatically next to the server plugin). + * Both keep a persistent `◪ supermemory` footer: blue while a session is + * running, otherwise the latest recall or save activity. OpenCode 2 also + * renders the server's activity notices as toasts here. + */ +import type { + TuiPlugin as V1TuiPlugin, + TuiPluginApi as V1TuiPluginApi, +} from "@opencode-ai/plugin/tui"; +import type { Plugin as TuiPlugin } from "@opencode/plugin/tui"; +import type { RGBA } from "@opentui/core"; +import { createSignal } from "solid-js"; + +import { + isSupermemoryActivityEvent, + SUPERMEMORY_ACTIVITY_EVENT, +} from "./rpc.js"; +import { + activityLabel, + DEFAULT_STATUS_ACTIVITY, + getRecallActivity, + recallLabel, + STATUS_PREFIX, + statusText, +} from "./tui-status.js"; + +type Color = string | RGBA; +const FALLBACK_RUNNING: Color = "#60a5fa"; +const FALLBACK_IDLE: Color = "#a78bfa"; + +function createStatus() { + const busy = new Set(); + const [running, setRunning] = createSignal(false); + const [activity, setActivity] = createSignal(DEFAULT_STATUS_ACTIVITY); + return { + running, + activity, + setActivity, + markBusy(sessionID: string | undefined) { + if (sessionID) busy.add(sessionID); + setRunning(busy.size > 0); + }, + markIdle(sessionID: string | undefined) { + if (sessionID) busy.delete(sessionID); + setRunning(busy.size > 0); + }, + }; +} + +// --------------------------------------------------------------------------- +// OpenCode V1 +// --------------------------------------------------------------------------- + +const tui: V1TuiPlugin = async (api: V1TuiPluginApi) => { + const status = createStatus(); + + api.event.on("session.status", (event) => { + const { sessionID, status: state } = event.properties; + if (state.type === "busy" || state.type === "retry") status.markBusy(sessionID); + else status.markIdle(sessionID); + }); + api.event.on("session.idle", (event) => { + status.markIdle(event.properties.sessionID); + }); + api.event.on("message.part.updated", (event) => { + const recalled = getRecallActivity(event.properties.part); + if (recalled) status.setActivity(recallLabel(recalled)); + }); + api.event.on("tui.toast.show", (event) => { + const message = event.properties.message; + if (message.startsWith(STATUS_PREFIX)) status.setActivity(activityLabel(message)); + }); + + api.slots.register({ + slots: { + app_bottom: () => ( + + + {statusText(status.running(), status.activity())} + + + ), + }, + }); +}; + +// --------------------------------------------------------------------------- +// OpenCode 2 +// --------------------------------------------------------------------------- + +type ThemeLike = { + text?: { + base?: Color; + muted?: Color; + action?: { primary?: { base?: Color } }; + feedback?: { + success?: { base?: Color }; + info?: { base?: Color }; + }; + }; +}; + +function v2StatusColor(theme: unknown, running: boolean): Color { + const text = (theme as ThemeLike | undefined)?.text; + if (running) { + return text?.feedback?.info?.base ?? text?.action?.primary?.base ?? FALLBACK_RUNNING; + } + return text?.feedback?.success?.base ?? text?.muted ?? FALLBACK_IDLE; +} + +function eventSessionID(event: unknown): string | undefined { + const data = (event as { data?: { sessionID?: unknown } }).data; + return typeof data?.sessionID === "string" ? data.sessionID : undefined; +} + +const setup: TuiPlugin.Definition["setup"] = (context) => { + const status = createStatus(); + const stops: Array<() => void> = []; + + stops.push( + context.data.on("session.execution.started", (event) => { + status.markBusy(eventSessionID(event)); + }), + ); + for (const type of [ + "session.execution.succeeded", + "session.execution.failed", + "session.execution.interrupted", + "session.idle", + "session.deleted", + ] as const) { + stops.push( + context.data.on(type, (event) => { + status.markIdle(eventSessionID(event)); + }), + ); + } + + stops.push( + context.data.listen(({ details }) => { + if (details.type !== SUPERMEMORY_ACTIVITY_EVENT) return; + const data = (details as { data?: unknown }).data; + if (!isSupermemoryActivityEvent(data)) return; + status.setActivity(activityLabel(data.message)); + context.ui.toast.show({ + title: data.title, + message: data.message, + variant: data.variant, + duration: data.duration, + }); + }), + ); + + const render = () => ( + + {statusText(status.running(), status.activity())} + + ); + stops.push(context.ui.slot({ append: "prompt.footer.status", render })); + stops.push(context.ui.slot({ append: "home.footer.status", render })); + + return () => { + for (const stop of stops.splice(0)) stop(); + }; +}; + +const plugin: TuiPlugin.Definition & { tui: V1TuiPlugin } = { + id: "supermemory.tui", + tui, + setup, +}; + +export default plugin; diff --git a/tsconfig.json b/tsconfig.json index d033272..2020c1b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,8 @@ "module": "ESNext", "moduleDetection": "force", "allowJs": true, + "jsx": "react-jsx", + "jsxImportSource": "@opentui/solid", // Bundler mode "moduleResolution": "bundler", diff --git a/tui.ts b/tui.ts index e71c754..d883c5d 100644 --- a/tui.ts +++ b/tui.ts @@ -1,2 +1,3 @@ // Local-development entry for the OpenCode 2 TUI companion (see server.ts). -export { default } from "./src/tui.ts"; +// Register the checkout in ~/.config/opencode/cli.json "plugins" for the TUI. +export { default } from "./src/tui.tsx"; From 90197f0a23b292eee79367cd65a2ef4d5d1732a4 Mon Sep 17 00:00:00 2001 From: Ishaan Gupta Date: Wed, 23 Sep 2026 21:09:55 +0530 Subject: [PATCH 3/4] Show the OpenCode 2 status footer once The prompt footer is rendered on the home screen too, so the extra home.footer.status slot duplicated the footer. --- README.md | 2 +- src/tui.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3603d42..3888124 100644 --- a/README.md +++ b/README.md @@ -205,7 +205,7 @@ server plugin. The same TUI plugin keeps a persistent `◪ supermemory` footer. It turns blue while a session is running and otherwise shows the latest recall or save activity. On OpenCode V1 the installer enables it through `~/.config/opencode/tui.jsonc`; on OpenCode 2 it appears -in the prompt and home footers without extra configuration. +in the prompt footer without extra configuration. Set `SUPERMEMORY_DEBUG=1` to show a `[recall-decision]` line in each reply while testing advisory recall. diff --git a/src/tui.tsx b/src/tui.tsx index c45339d..6fae960 100644 --- a/src/tui.tsx +++ b/src/tui.tsx @@ -161,8 +161,9 @@ const setup: TuiPlugin.Definition["setup"] = (context) => { {statusText(status.running(), status.activity())} ); + // The prompt footer is present on both the home screen and in sessions, so + // one slot is enough; a second entry in home.footer.status would duplicate it. stops.push(context.ui.slot({ append: "prompt.footer.status", render })); - stops.push(context.ui.slot({ append: "home.footer.status", render })); return () => { for (const stop of stops.splice(0)) stop(); From bbc5bc1cea548d81a6259dcb045540e17af2e917 Mon Sep 17 00:00:00 2001 From: Ishaan Gupta Date: Wed, 23 Sep 2026 21:11:11 +0530 Subject: [PATCH 4/4] Show a bare supermemory footer until there is activity --- README.md | 2 +- src/tui-status.test.ts | 1 + src/tui-status.ts | 7 +++++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3888124..cd331ed 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ context. On OpenCode V1 they are TUI toasts; on OpenCode 2 they are rendered by server plugin. The same TUI plugin keeps a persistent `◪ supermemory` footer. It turns blue while a -session is running and otherwise shows the latest recall or save activity. On OpenCode V1 +session is running and otherwise shows the latest recall or save activity, if any. On OpenCode V1 the installer enables it through `~/.config/opencode/tui.jsonc`; on OpenCode 2 it appears in the prompt footer without extra configuration. diff --git a/src/tui-status.test.ts b/src/tui-status.test.ts index 72d2262..cb39fc7 100644 --- a/src/tui-status.test.ts +++ b/src/tui-status.test.ts @@ -33,5 +33,6 @@ describe("status footer helpers", () => { expect(activityLabel("other")).toBe("other"); expect(statusText(true, "saved this turn")).toBe(`${STATUS_PREFIX}running`); expect(statusText(false, "saved this turn")).toBe(`${STATUS_PREFIX}saved this turn`); + expect(statusText(false, "")).toBe("◪ supermemory"); }); }); diff --git a/src/tui-status.ts b/src/tui-status.ts index 4132598..d97f7ff 100644 --- a/src/tui-status.ts +++ b/src/tui-status.ts @@ -3,7 +3,9 @@ * V1 and OpenCode 2 TUI plugins. Kept free of JSX so they can be unit tested. */ export const STATUS_PREFIX = "◪ supermemory · "; -export const DEFAULT_STATUS_ACTIVITY = "ready"; +export const STATUS_LABEL = "◪ supermemory"; +/** Idle with no activity yet shows just the label, without a suffix. */ +export const DEFAULT_STATUS_ACTIVITY = ""; export interface RecallActivity { count: number; @@ -53,5 +55,6 @@ export function activityLabel(message: string): string { } export function statusText(running: boolean, activity: string): string { - return `${STATUS_PREFIX}${running ? "running" : activity}`; + if (running) return `${STATUS_PREFIX}running`; + return activity ? `${STATUS_PREFIX}${activity}` : STATUS_LABEL; }