diff --git a/AGENTS.md b/AGENTS.md index e83cc36..c04a31c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,6 +53,18 @@ via the drift script before proposing structural changes. first, followed only by the built-in opencode file tools it requires. Never allow shell, network, task delegation, IDE, or MCP tools; that is the sandbox (D2), and `tests/agents.test.ts` enforces it. +- opencode2 support lives in `src/v2/` and reuses the V1 pipeline unchanged + via a V1-client shim (`src/v2/shim.ts`); see `docs/opencode2.md` for the + deliberate V2 adaptations. Rules: never edit V1 behavior for V2 needs (adapt + in `src/v2/`), the `agents` map in `opencode.json` follows the same + allowlist rule as `agent` (V2 action names: `edit` covers write/patch; + `tests/v2-agents.test.ts` enforces it), and `bun run contract:v2` must pass + alongside `bun run contract`. The `./tui` entry (`src/v2/tui.tsx`, RPC in + `src/v2/status-rpc.ts`) adds the sidebar section: `setup()` must only claim + slots (Solid-scoped APIs like `keymap.layer` belong in slot components), + the TUI bundle may import only `@opencode/plugin/tui` + `solid-js` + + `@opentui/solid`, and `bun run build` compiles the JSX via + `scripts/build-tui.ts`. ## Packaging & releases diff --git a/README.md b/README.md index 821d072..a6fbf7e 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,20 @@ learning starts immediately. Requires OpenCode 1.18 or newer. Models and other options: see [Configuration](#configuration). +**OpenCode 2:** the same package works on opencode2 — install it with the +V2 plugin syntax: + +```jsonc +{ + "plugins": [{ "package": "opencode-codex-memory@0.6.5" }], +} +``` + +Behavior is identical; see [docs/opencode2.md](./docs/opencode2.md) for the +few platform adaptations and current limitations. On opencode2 you also get a +**Memory** section in the session sidebar plus a `/memory-status` command, +served live from the same state as `memory_inspect`. + ### Installation hints To bump pins, copy diff --git a/bun.lock b/bun.lock index abbd8c3..f146548 100644 --- a/bun.lock +++ b/bun.lock @@ -6,19 +6,163 @@ "name": "opencode-codex-memory", "dependencies": { "@opencode-ai/plugin": "^1.18.0", + "@opencode/plugin": "0.0.0-beta-19296", "diff": "^9.0.0", "isomorphic-git": "^1.38.6", "xdg-basedir": "^5.1.0", + "zod": "4.1.8", }, "devDependencies": { + "@opencode/theme": "0.0.0-beta-19296", + "@opentui/core": "0.5.10", + "@opentui/solid": "0.5.10", "@types/bun": "^1.1.0", + "solid-js": "1.9.15", "typescript": "^5.5.0", }, + "peerDependencies": { + "@opentui/core": ">=0.5.10", + "@opentui/solid": ">=0.5.10", + "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=="], + + "@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.977.9", "", { "dependencies": { "@aws-sdk/types": "^3.974.5", "@aws-sdk/xml-builder": "^3.972.40", "@aws/lambda-invoke-store": "^0.3.0", "@smithy/core": "^3.33.3", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.17.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-reqPFEQrZxDZpeGj4PFMepBeR5LGYHRqq/L0motTzgFkCRBA4rFdaVXDSLYyGHhxVz7sT2PDnPN9CluGSfgyJA=="], + + "@aws-sdk/credential-provider-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.972.69", "", { "dependencies": { "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-vpsh9VWmQVC/nsdzf72F2yUMBOFT1aq+hoLseYV03zjVXVHkjqSNJskFRKPFxc3MRFrHNbSSmOwsbYE15u9ecw=="], + + "@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.70", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-H404B7dJl2mCrBqahDEYsanB0xhdDp6tXnXcTUnXmmpy2Q3J0Ho0bUajZ2jr/RdwzCyS59Gi8xXIFwPLGBl6Uw=="], + + "@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.72", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/fetch-http-handler": "^5.7.2", "@smithy/node-http-handler": "^4.11.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-X98zYOrVOeuosCX+6ktf29FC2N2GHPLia7qv6mzPzTc+RPAuHWCDS++Z6JK7eGYqb/v6uaW7bAXaOvDBfol+0w=="], + + "@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.973.15", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/credential-provider-env": "^3.972.70", "@aws-sdk/credential-provider-http": "^3.972.72", "@aws-sdk/credential-provider-login": "^3.972.77", "@aws-sdk/credential-provider-process": "^3.972.70", "@aws-sdk/credential-provider-sso": "^3.973.14", "@aws-sdk/credential-provider-web-identity": "^3.972.76", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-Rykg6s5ceBuynMOGWgoowO4N+27JfnqXAnVaSunZl0hOO1XodSrxGNz6sCEbnmS0lAfQZDKyb3fbr46gSuv6Sg=="], + + "@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.77", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-Jb59xfEISoN5mmbnA+HYqdtrSX3CgCtJoof+V5D8/TgUI56W63GEEd5Y58WijU3Ou6+WEgaLD1feVzaRXV5IDQ=="], + + "@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.82", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.70", "@aws-sdk/credential-provider-http": "^3.972.72", "@aws-sdk/credential-provider-ini": "^3.973.15", "@aws-sdk/credential-provider-process": "^3.972.70", "@aws-sdk/credential-provider-sso": "^3.973.14", "@aws-sdk/credential-provider-web-identity": "^3.972.76", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/credential-provider-imds": "^4.4.16", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-znDkEOGXB8W3kG1LJUKP3foBZY/9qLM0eil/DxWXSp37XsdsRLQHE/d/OaCGGVgKpA6znR38h/+INk8do1FjiA=="], + + "@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.70", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-2ry03fGRJr4sV3jI+ocjj5JqALnFD6ymM5KiNCDZMvq8bX2GSbE0vji4aM43TVCl2nXqqLRZaUxdq/KeWRAY4Q=="], + + "@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.973.14", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/token-providers": "3.1116.0", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-jkhg/8ocAAoc0RFyLMhCw+/zZh7gystQgd4F4hznNa8P4Cc501PQmxd+jGLiMHodPJ+7Zv/3znM62gZojyasmA=="], + + "@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.76", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-d3AGyVu759PGr35mEB2s22xxlNEA5rpdxtSPJthfPFJvoQ8dt357iVPECqWfUxXp1toJAvKmbtcIYVGigaGsCA=="], + + "@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.44", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/signature-v4-multi-region": "^3.996.46", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/fetch-http-handler": "^5.7.2", "@smithy/node-http-handler": "^4.11.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-NhEgryjlBF9w38ZXqGymQV28IhkYa1mKhlbYnqIis57AYwWGVYfUPgg/qC2rLRqOUfblxx++irvju10kVTa8Vw=="], + + "@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.46", "", { "dependencies": { "@aws-sdk/types": "^3.974.5", "@smithy/signature-v4": "^5.6.12", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ=="], + + "@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1116.0", "", { "dependencies": { "@aws-sdk/core": "^3.977.9", "@aws-sdk/nested-clients": "^3.997.44", "@aws-sdk/types": "^3.974.5", "@smithy/core": "^3.33.3", "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-ygIivKqh8aHzNkucOCXHyIBgBpLPfrSI0mCqXF+vLBsPTUKqj0VSqAY0GFPe7lQl4HntjOcQ+KSyS7oUV2C54Q=="], + + "@aws-sdk/types": ["@aws-sdk/types@3.974.5", "", { "dependencies": { "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ=="], + + "@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.40", "", { "dependencies": { "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA=="], + + "@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.8", "", { "dependencies": { "@babel/types": "^7.29.8" }, "bin": "./bin/babel-parser.js" }, "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA=="], + + "@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.7", "", { "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-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw=="], + + "@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=="], + + "@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=="], + + "@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=="], @@ -31,40 +175,264 @@ "@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.18.10", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode-ai/sdk": "1.18.10", "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-l4R1ulu5wtA0+cCinzdSPkEO8ZCdIgb/ZjltzstIWQqRqeH3H880OabNaeje/ZCkSoAT8c/o9oT3tdjyFP7o7g=="], "@opencode-ai/sdk": ["@opencode-ai/sdk@1.18.10", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-K+glWbBp5pfGepZ/6EHvuXY3IpVG2qgsEqF4z9mOiUQUrs6KWN72Vdp15Qsl2TCDbemgHWXKQKgbX3b8PSK2hg=="], + "@opencode/ai": ["@opencode/ai@0.0.0-beta-19296", "", { "dependencies": { "@aws-sdk/credential-providers": "3.1057.0", "@opencode/schema": "0.0.0-beta-19296", "@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-os3dldWWHXqaem6ksmxEXTx9K9PVkYi0/uD0X8pRSBNZ1rPTANTBoZfVybNjdfWs9ByTKeVDaLzu/66s/yw2Vg=="], + + "@opencode/client": ["@opencode/client@0.0.0-beta-19296", "", { "dependencies": { "@opencode/protocol": "0.0.0-beta-19296", "@opencode/schema": "0.0.0-beta-19296" }, "peerDependencies": { "effect": "4.0.0-rc.112", "solid-js": ">=1.9.0" }, "optionalPeers": ["effect", "solid-js"] }, "sha512-2UtyI1Bkq5PWOo+hWrGQawLjQ9+k+TgZPmUIN4aqr6cUlmKThVycxNoScN7NSUc4Y79qTSM8FM3qtEU6rkSF7A=="], + + "@opencode/plugin": ["@opencode/plugin@0.0.0-beta-19296", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@opencode/ai": "0.0.0-beta-19296", "@opencode/client": "0.0.0-beta-19296", "@opencode/protocol": "0.0.0-beta-19296", "@opencode/schema": "0.0.0-beta-19296", "@opencode/util": "0.0.0-beta-19296", "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112", "zod": "4.1.8" }, "peerDependencies": { "@opencode/theme": "0.0.0-beta-19296", "@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-ci/cMYttDD0cmOdN9v4+NoKx+eVDTS61e0HueK9rpnQ9VAacDtmuq+f5bu/7sMddGHcC/67fXDrPtsEtbNO9IQ=="], + + "@opencode/protocol": ["@opencode/protocol@0.0.0-beta-19296", "", { "dependencies": { "@opencode/schema": "0.0.0-beta-19296", "effect": "4.0.0-rc.112" } }, "sha512-N36usL362is3T9CAqPIr4r2zfvvVrm3QNQRo4HNWxsz7cdvcm5Pi/5j0j7MxRTCRzUbhCcFaJuskiP4iKGs30g=="], + + "@opencode/schema": ["@opencode/schema@0.0.0-beta-19296", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "effect": "4.0.0-rc.112" } }, "sha512-X2TlT0O8by3VvqiyxECF/mYIjCJVObr5tx8tGBM+ZkL87sSom4d6rNGeAgw9+acmy1YDBSX6vC9eaF/LGNFmbw=="], + + "@opencode/theme": ["@opencode/theme@0.0.0-beta-19296", "", { "dependencies": { "@opentui/core": "0.5.10", "effect": "4.0.0-rc.112" } }, "sha512-XXsTa67YfOSArqhsjQMARDtZ1pJ2JDEjOeGpNgSXwn8emymJg9kGuHL8Jz79R2YIZW8eahiKqQbbEQGcrkgWmw=="], + + "@opencode/util": ["@opencode/util@0.0.0-beta-19296", "", { "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-aD3lUdvmn37EQBds7vtAKf7VbISbWQi8xC+24ctJbe3TdBawy/JM6CwKzwe2uBxYHedvfAyUWS3NWsLDbDipBA=="], + + "@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=="], + + "@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=="], + + "@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.33.3", "", { "dependencies": { "@smithy/types": "^4.17.2", "tslib": "^2.6.2" } }, "sha512-CsOeKq/9kA3y6VJHt+/+VTCtBaxJ4OTFpgrjIUhPpDIKxBci1k2bJaQASF2h/ELWrulGp+t97DZ0mevfAD8idg=="], + + "@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.18.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A=="], + + "@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.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], "@types/node": ["@types/node@26.1.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw=="], + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], + "abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="], + "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=="], + "async-lock": ["async-lock@1.4.1", "", {}, "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ=="], "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + "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.21", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ=="], + + "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.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], + + "browserslist": ["browserslist@4.28.9", "", { "dependencies": { "baseline-browser-mapping": "^2.11.20", "caniuse-lite": "^1.0.30001810", "electron-to-chromium": "^1.5.420", "node-releases": "^2.0.54", "update-browserslist-db": "^1.3.2" }, "bin": { "browserslist": "cli.js" } }, "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg=="], + "buffer": ["buffer@6.0.3", "", { "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" } }, "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA=="], + "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.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], + "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=="], + "call-bind": ["call-bind@1.0.9", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" } }, "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + "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=="], + "clean-git-ref": ["clean-git-ref@2.0.1", "", {}, "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw=="], + "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=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + "crc-32": ["crc-32@1.2.2", "", { "bin": { "crc32": "bin/crc32.njs" } }, "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ=="], "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=="], + "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], @@ -77,7 +445,19 @@ "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], - "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=="], + "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=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.423", "", {}, "sha512-rRZfTSY8ptHYMQxa+uIycJMFKmY1T0GIApNMXJYGehguTZa56TEEl19pKPCoBqk5Gpf7QizZn/jt7xur+DYxag=="], + + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + + "entities": ["entities@7.0.1", "", {}, "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA=="], + + "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], @@ -85,24 +465,64 @@ "es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "event-target-shim": ["event-target-shim@5.0.1", "", {}, "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="], "events": ["events@3.3.0", "", {}, "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="], - "fast-check": ["fast-check@4.8.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg=="], + "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.9.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-7ms6T7SybUev/PQITciI0yLM2pOSFy5zpG8Ty7tQofcVaQUvrMXp6CBwqF6fThLCLOrfBtuHAtwq6Yu4XPCllg=="], + + "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=="], + + "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=="], + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "^1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + "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.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + "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=="], + + "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=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "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=="], + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], @@ -111,16 +531,36 @@ "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=="], + + "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=="], + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + "ignore-walk": ["ignore-walk@8.0.0", "", { "dependencies": { "minimatch": "^10.0.3" } }, "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A=="], + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], "ini": ["ini@7.0.0", "", {}, "sha512-ifK0CgjALofS5bkrcTy4RaQ9Vx2Knf/eLeIO+NaswQEpH1UblrtTSCIvN71qQDMq0PeQ/SSPojvEJp9vvvfr+w=="], + "ip-address": ["ip-address@10.7.0", "", {}, "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA=="], + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + "is-core-module": ["is-core-module@2.16.2", "", { "dependencies": { "hasown": "^2.0.3" } }, "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "^1.1.16" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], @@ -129,44 +569,188 @@ "isomorphic-git": ["isomorphic-git@1.38.6", "", { "dependencies": { "async-lock": "^1.4.1", "clean-git-ref": "^2.0.1", "crc-32": "^1.2.0", "diff3": "0.0.3", "ignore": "^5.1.4", "minimisted": "^2.0.0", "pako": "^1.0.10", "pify": "^4.0.1", "readable-stream": "^4.0.0", "sha.js": "^2.4.12", "simple-get": "^4.0.1" }, "bin": { "isogit": "cli.cjs" } }, "sha512-lCmZ1m2R0LqbZ4QATtLCxhwNBQPNJc74R81dfyF90yLqP8xs2DZLedcnkVuRj6th/L2HYoIvWP5lBpS1ooAagw=="], + "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=="], + "json-schema": ["json-schema@0.4.0", "", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], + "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=="], + + "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=="], + "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@5.1.1", "", { "dependencies": { "yallist": "^3.0.2" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "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=="], + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + "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=="], + "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], + "minimatch": ["minimatch@10.2.5", "", { "dependencies": { "brace-expansion": "^5.0.5" } }, "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], "minimisted": ["minimisted@2.0.1", "", { "dependencies": { "minimist": "^1.2.5" } }, "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA=="], - "msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="], + "minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], + + "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=="], "multipasta": ["multipasta@0.2.7", "", {}, "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA=="], + "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=="], + "node-releases": ["node-releases@2.0.54", "", {}, "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ=="], + + "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=="], + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + "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.7", "", {}, "sha512-VaWRu2i4FJNRtiRWCuuQRgfQ1B7a6+gMSrO+3j0EQi/k0ULfS9kosRxGoiqwzIjZTDI02tGfk5mXXltLg6QtfQ=="], + + "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=="], + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + "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@1.11.1", "", { "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.7", "", {}, "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA=="], + "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], + "pkg-up": ["pkg-up@3.1.0", "", { "dependencies": { "find-up": "^3.0.0" } }, "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA=="], + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + "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=="], + "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], + "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.1", "", {}, "sha512-c58R2+SPFcSIPXoU834QN/KPDDOSd8sXcSrqf6e83Me6Rrp1EYkxukkjXMVrKvKaADs1SOyNkWdfvLf6zY8qLQ=="], + "read-cmd-shim": ["read-cmd-shim@6.0.0", "", {}, "sha512-1zM5HuOfagXCBWMN83fuFI/x+T/UhZ7k+KIzhrHXcQoeX5+7gmaDYjELQHmmzIodumBHeByBJT4QYS7ufAgs7A=="], + "readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="], + "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@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=="], + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], "sha.js": ["sha.js@2.4.12", "", { "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1", "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" } }, "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w=="], @@ -175,34 +759,282 @@ "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=="], + "simple-concat": ["simple-concat@1.0.1", "", {}, "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="], "simple-get": ["simple-get@4.0.1", "", { "dependencies": { "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } }, "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="], + "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=="], + + "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=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.23", "", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], + + "ssri": ["ssri@13.0.1", "", { "dependencies": { "minipass": "^7.0.3" } }, "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ=="], + + "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=="], + "string_decoder": ["string_decoder@1.3.0", "", { "dependencies": { "safe-buffer": "~5.2.0" } }, "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA=="], + "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=="], + + "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=="], + "to-buffer": ["to-buffer@1.2.2", "", { "dependencies": { "isarray": "^2.0.5", "safe-buffer": "^5.2.1", "typed-array-buffer": "^1.0.3" } }, "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw=="], "toml": ["toml@4.1.2", "", {}, "sha512-m0vXfHODcw3gk+KONAOlVQ5yNHc3yS3B1ybM3HS1vqDoS0RWTDDVBVVTYi8hH0k+2OM1vmo9fb1WX9EVqjqfHA=="], + "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=="], + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "is-typed-array": "^1.1.14" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "undici": ["undici@8.10.2", "", {}, "sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ=="], + "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], + "update-browserslist-db": ["update-browserslist-db@1.3.2", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "uuid": ["uuid@14.0.1", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew=="], + "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=="], "which-typed-array": ["which-typed-array@1.1.22", "", { "dependencies": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.9", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" } }, "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw=="], + "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=="], + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + "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=="], + "xdg-basedir": ["xdg-basedir@5.1.0", "", {}, "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ=="], + "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], "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=="], + + "@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=="], + + "@isaacs/fs-minipass/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@npmcli/agent/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "@npmcli/arborist/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "@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/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "@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/map-workspaces/glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], + + "@npmcli/metavuln-calculator/semver": ["semver@7.8.5", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA=="], + + "@npmcli/package-json/glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], + + "@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/plugin/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=="], + + "@opencode/util/glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], + + "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=="], + + "cacache/glob": ["glob@13.0.5", "", { "dependencies": { "minimatch": "^10.2.1", "minipass": "^7.1.2", "path-scurry": "^2.0.0" } }, "sha512-BzXxZg24Ibra1pbQ/zE7Kys4Ua1ks7Bn6pKLkVPZ9FZe4JQS6/Q7ef3LG1H+k7lUf5l4T3PLSyYyYJVYUvfgTw=="], + + "cacache/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "cacache/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "fs-minipass/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "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=="], + + "glob/minimatch": ["minimatch@8.0.7", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg=="], + + "hosted-git-info/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "make-fetch-happen/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "minipass-collect/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "minipass-fetch/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "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=="], + + "minipass-sized/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "minizlib/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "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=="], + + "npm-registry-fetch/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "pacote/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "parse5/entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], + + "path-scurry/lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], + + "path-scurry/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "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=="], + + "ssri/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "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=="], + + "tar/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "tar/yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + + "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=="], + + "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=="], + + "@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/map-workspaces/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@npmcli/map-workspaces/glob/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=="], + + "@npmcli/package-json/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@npmcli/package-json/glob/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=="], + + "@npmcli/promise-spawn/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + + "@opencode-ai/plugin/effect/fast-check": ["fast-check@4.8.0", "", { "dependencies": { "pure-rand": "^8.0.0" } }, "sha512-GOJ158CUMnN6cSahsv4+ExARvIDuzzinFjkp0E9WtiBa5zcVeLozVkWaE4IzFcc+Y48Wp1EDlUZsXRyAztQcSg=="], + + "@opencode-ai/plugin/effect/msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="], + + "@opencode/util/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "@opencode/util/glob/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=="], + + "cacache/glob/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=="], + + "glob/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="], + + "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/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "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=="], + + "wrap-ansi/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "@npmcli/map-workspaces/glob/path-scurry/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "@npmcli/package-json/glob/path-scurry/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "@opencode/util/glob/path-scurry/lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], + + "glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="], + + "rimraf/glob/minimatch/brace-expansion/balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], } } diff --git a/docs/opencode2.md b/docs/opencode2.md new file mode 100644 index 0000000..f4f4b2a --- /dev/null +++ b/docs/opencode2.md @@ -0,0 +1,103 @@ +# opencode2 support + +This plugin runs on both hosts from a single package entry: + +- opencode 1.x reads `server()` (V1 hooks, `opencode.json` → `agent` map). +- opencode2 reads `id` + `setup()` (V2 context API, `src/v2/*` adapter). + +Install for opencode2: + +```jsonc +// opencode.jsonc +{ + "$schema": "https://opencode.ai/config.json", + "plugins": [ + { "package": "opencode-codex-memory@0.6.5", "options": { "min_rollout_idle_hours": 1 } }, + ], +} +``` + +All V1 plugin options (`generate_memories`, `use_memories`, +`dedicated_tools`, `disable_on_external_context`, `extract_model`, +`consolidation_model`, numeric clamps, `codex_interop`, `claude_import`) +apply unchanged — option parsing is shared (`applyPluginOptions`). + +## How it works + +The entire memory pipeline (extraction → consolidation → injection → +citation feedback against the global `~/.local/share/opencode` workspace) +runs byte-identical on both hosts. `src/v2/shim.ts` presents a V1-shaped +client façade over the V2 plugin context, so `phase1/phase2/capture/llm` +execute the same code paths. Only genuinely missing V2 surfaces are +adapted; everything else is hook translation (`src/v2/plugin.ts`): + +| V1 | V2 | +| --- | --- | +| `config` hook agent injection | `agent.transform` ensure (update creates) | +| returned `tool` map | `tool.transform` (same `tools/*` logic via adapter) | +| `chat.message` pump | `prompt` hook | +| `system.transform` injection | `context` hook (`system.push({type:"text",…})`) | +| `text.complete` + `messages.transform` citations | `context` hook record + strip | +| `tool.execute.before` pollution | `tool.execute.before` (same hook name) | +| `session.status idle` / `session.idle` pump | `session.execution.succeeded` event | +| `session.deleted` cleanup | liveness (`session.get` → NotFound) in phase 2 | +| `experimental/session` global discovery | process-local session registry | + +## Deliberate V2 differences + +- **No session deletion.** V2 has no remove API. Helper sessions are + interrupted and released; their rows remain as inert, clearly titled + (`codex-memory-*`) history. Extraction uses `generate.text` and creates + no session at all. +- **Registry-based discovery.** `ctx` exposes no session list and raw HTTP + is unauthenticated from plugins, so discovery reads sessions observed via + `session.created` + the prompt hook (with `parentID` backfill to keep + excluding subagent children). A cold boot sees sessions from admission + on; prior extraction rows still drive consolidation. +- **Citations stripped from model context only.** V2 has no pre-persist + hook, so `` markup stays in stored history (visible in + the UI) while the context hook removes it before every model call. + Usage counts are exact within a process (per-message dedupe). +- **No `small_model`/`model` config defaults.** V2 exposes no config API + to plugins, so unset `extract_model`/`consolidation_model` fall back to + the session default. Set them explicitly to mirror V1 model routing. +- **Both agents ship; only `memorize` works.** Extraction runs sessionless + through `generate.text`, so `memorize-extract` is provisioned hidden and + unused (V1 likewise skips injecting unused agents). + +## Sidebar status + +The package's `./tui` entry adds a **Memory** section to the session sidebar. +OpenCode2 loads it automatically alongside the server plugin. `/memory-status` +(also **Show memory status** in the command palette) opens effective models, +read/write settings, import status, retry eligibility, and warnings. + +- Status is global, using the same job snapshots as `memory_inspect`. +- The UI refreshes on pipeline events and reconciles every five seconds while + loaded, including changes made by another worker; viewing it never starts jobs. +- A disconnected or unavailable server shows **Unavailable**, not stale **Idle**. +- **Last success** is shown only when the latest recorded consolidation attempt + succeeded; `—` means no clean success timestamp is available for that attempt. +- TUI dependencies are optional peers supplied by OpenCode2; V1 loads only the + server entry. The build compiles Solid JSX and ships the result under `dist/`. +- TUI rules learned the hard way: `setup()` must only claim slots — + `keymap.layer` throws outside a Solid component scope, so it lives in an + `app`-slot component; never render `` (or any conditional) with element + children directly under `` — its empty placeholder is a bare text node + and the renderer rejects it. Use unconditional lines with placeholders. +- The TUI bundle must import only `@opencode/plugin/tui`, `solid-js`, and + `@opentui/solid`: the CLI sandbox does not resolve `zod` or + `@opencode/plugin/rpc`, so the status contract (`src/v2/status-rpc.ts`) is + plain JSON Schema with a hand-written guard. + +For a local wrapper, add `tui.ts` beside its `index.ts`, re-exporting the built +`dist/src/v2/tui.js` default export, then run `bun run build` in this repository. + +## Verify + +```bash +bun run typecheck && bun test && bun run build +bun run smoke # V1 entry +bun run contract # V1 host surface +bun run contract:v2 # V2 host surface (needs the opencode2 service) +``` diff --git a/opencode.json b/opencode.json index b8cc82b..cb54853 100644 --- a/opencode.json +++ b/opencode.json @@ -36,5 +36,26 @@ "StructuredOutput": "allow" } } + }, + "agents": { + "memorize": { + "description": "Memory consolidation agent (opencode-codex-memory)", + "mode": "subagent", + "system": "You are a memory consolidation agent. Read the workspace diff file and update MEMORY.md, memory_summary.md, and skills/ under the memory workspace only. Do not read or edit project source files outside that memory root. Keep memory_summary.md under 10000 chars (2500 tokens). Prune stale entries. Do not access the network.", + "permissions": [ + { "action": "*", "resource": "*", "effect": "deny" }, + { "action": "read", "resource": "*", "effect": "allow" }, + { "action": "edit", "resource": "*", "effect": "allow" }, + { "action": "glob", "resource": "*", "effect": "allow" }, + { "action": "grep", "resource": "*", "effect": "allow" } + ] + }, + "memorize-extract": { + "description": "Memory extraction agent (opencode-codex-memory)", + "mode": "subagent", + "hidden": true, + "system": "You are a memory extraction agent. The session transcript is provided inline in the prompt. Extract raw_memory, rollout_summary, and rollout_slug as JSON. Exclude AGENTS.md/instruction content. Redact secrets.", + "permissions": [{ "action": "*", "resource": "*", "effect": "deny" }] + } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index ab903db..95ef32d 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,14 @@ "import": "./dist/src/index.js", "types": "./dist/src/index.d.ts" }, + "./v2": { + "import": "./dist/src/v2/index.js", + "types": "./dist/src/v2/index.d.ts" + }, + "./tui": { + "types": "./dist/src/v2/tui.d.ts", + "import": "./dist/src/v2/tui.js" + }, "./tools/*": { "import": "./dist/tools/*.js", "types": "./dist/tools/*.d.ts" @@ -29,9 +37,10 @@ }, "scripts": { "dev": "bun --watch src/index.ts", - "build": "tsc && rm -rf dist/src/templates && cp -R src/templates dist/src/templates && cp opencode.json dist/opencode.json", + "build": "tsc && bun scripts/build-tui.ts && rm -rf dist/src/templates && cp -R src/templates dist/src/templates && cp opencode.json dist/opencode.json", "smoke": "bun scripts/smoke.ts", "contract": "bun scripts/check-opencode-contract.ts", + "contract:v2": "bun scripts/check-opencode2-contract.ts", "live:read": "bun scripts/live-readpath.ts", "live:e2e": "bun scripts/live-e2e.ts", "prepack": "npm run build && npm run smoke", @@ -49,14 +58,30 @@ "license": "Apache-2.0", "dependencies": { "@opencode-ai/plugin": "^1.18.0", + "@opencode/plugin": "0.0.0-beta-19296", "diff": "^9.0.0", "isomorphic-git": "^1.38.6", - "xdg-basedir": "^5.1.0" + "xdg-basedir": "^5.1.0", + "zod": "4.1.8" }, "devDependencies": { + "@opencode/theme": "0.0.0-beta-19296", + "@opentui/core": "0.5.10", + "@opentui/solid": "0.5.10", + "solid-js": "1.9.15", "typescript": "^5.5.0", "@types/bun": "^1.1.0" }, + "peerDependencies": { + "@opentui/core": ">=0.5.10", + "@opentui/solid": ">=0.5.10", + "solid-js": ">=1.9.0" + }, + "peerDependenciesMeta": { + "@opentui/core": { "optional": true }, + "@opentui/solid": { "optional": true }, + "solid-js": { "optional": true } + }, "engines": { "bun": ">=1.1.0" } diff --git a/scripts/build-tui.ts b/scripts/build-tui.ts new file mode 100644 index 0000000..c5786fb --- /dev/null +++ b/scripts/build-tui.ts @@ -0,0 +1,13 @@ +import solid from "@opentui/solid/bun-plugin" + +const result = await Bun.build({ + entrypoints: ["./src/v2/tui.tsx"], + outdir: "./dist/src/v2", + target: "bun", + format: "esm", + packages: "external", + plugins: [solid], +}) +if (!result.success) throw new AggregateError(result.logs, "TUI build failed") +// tsc emits preserved JSX for declarations; only the Solid-compiled JS ships. +await Bun.file("./dist/src/v2/tui.jsx").delete() diff --git a/scripts/check-opencode2-contract.ts b/scripts/check-opencode2-contract.ts new file mode 100644 index 0000000..f580569 --- /dev/null +++ b/scripts/check-opencode2-contract.ts @@ -0,0 +1,151 @@ +/** + * V2 contract check for the opencode2 host adapter (src/v2/*). + * + * No LLM, no auth, no Docker. Safe for every PR / pre-release ritual. + * + * Checks: + * 1. opencode2 binary present; version ≥ floor (OPENCODE2_MIN_VERSION, + * default 0.0.0-beta-19296 — the beta this adapter was verified against) + * 2. Live OpenAPI (/openapi.json via the background service): every + * operation the shim + setup depend on is present + * 3. Built plugin dual-exports V1 server() and V2 setup() + * 4. V2 memorize agent satisfies the deny-first allowlist shape + * 5. V2 tool registration yields the expected 7/3 tool sets + * + * Exit 0 = aligned. Exit 1 = contract break. Exit 2 = setup error. + */ +import fs from "fs" +import os from "os" +import path from "path" +import { $ } from "bun" + +const MIN_VERSION = process.env.OPENCODE2_MIN_VERSION?.trim() || "0.0.0-beta-19296" + +let failed = 0 +function log(kind: string, msg: string): void { + console.log(`[${kind}] ${msg}`) +} +function note(ok: boolean, msg: string): void { + if (ok) log("ok", msg) + else { + console.error(`[fail] ${msg}`) + failed++ + } +} +function failSetup(msg: string): never { + console.error(`[setup] ${msg}`) + process.exit(2) +} + +function betaNum(v: string): number | null { + const m = v.trim().match(/beta-(\d+)/) + return m ? Number(m[1]) : null +} + +// Semver-ish compare with beta-suffix awareness for 0.0.0-beta-NNN. +function versionGte(a: string, b: string): boolean { + const an = betaNum(a) + const bn = betaNum(b) + if (an !== null && bn !== null) { + const [acore] = a.split("-beta-") + const [bcore] = b.split("-beta-") + if (acore !== bcore) return acore > bcore + return an >= bn + } + return a >= b +} + +const REQUIRED_OPS = [ + "v2.session.create", + "v2.session.get", + "v2.session.prompt", + "v2.session.wait", + "v2.session.context", + "v2.session.generate", + "v2.session.switchAgent", + "v2.session.switchModel", + "v2.session.interrupt", + "v2.generate.text", + "v2.mcp.list", + "v2.agent.get", + "v2.event.subscribe", + "v2.model.list", +] as const + +async function main(): Promise { + // --- binary --- + let version = "" + try { + version = (await $`opencode2 --version`.text()).trim() + } catch { + failSetup("opencode2 binary not found on PATH") + } + log("bin", `opencode2 @ ${version}`) + note(versionGte(version, MIN_VERSION), `opencode2 ${version} ≥ ${MIN_VERSION}`) + + // --- OpenAPI via the background service (no auth needed for /openapi.json) --- + let doc: { paths?: Record> } + try { + const raw = await $`opencode2 api get /openapi.json`.text() + doc = JSON.parse(raw) + } catch (e) { + failSetup(`could not fetch /openapi.json: ${e instanceof Error ? e.message : String(e)}`) + } + const ops = new Set() + for (const methods of Object.values(doc.paths ?? {})) { + for (const spec of Object.values(methods)) { + if (spec?.operationId) ops.add(spec.operationId) + } + } + note(ops.size > 0, `openapi has ${ops.size} operations`) + for (const op of REQUIRED_OPS) { + note(ops.has(op), `operation ${op} present`) + } + + // --- built plugin dual export --- + const root = path.resolve(import.meta.dirname, "..") + const testRoot = fs.mkdtempSync(path.join(os.tmpdir(), "ocm-contract2-plugin-")) + process.env.OPENCODE_CODEX_MEMORY_TEST_ROOT = testRoot + try { + const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8")) + const entry = path.resolve(root, pkg.main) + if (!fs.existsSync(entry)) failSetup(`main entry ${pkg.main} missing — run build first`) + const mod = await import(entry + `?t=${Date.now()}`) + note(typeof mod.default?.server === "function", "default export keeps V1 server()") + note(typeof mod.default?.setup === "function", "default export adds V2 setup()") + note(mod.default?.id === "opencode-codex-memory", "plugin id unchanged") + + const v2entry = path.resolve(root, pkg.exports?.["./v2"]?.import ?? "./dist/src/v2/index.js") + if (!fs.existsSync(v2entry)) failSetup(`v2 entry missing — run build first`) + const v2mod = await import(v2entry + `?t=${Date.now()}`) + note(typeof v2mod.default?.setup === "function", "./v2 entry exports setup()") + + // --- V2 agent shape (D2 allowlist, V2 action names) --- + const agents = (await import(path.join(root, "dist", "src", "v2", "agents.js") + `?t=${Date.now()}`)) as typeof import("../src/v2/agents.js") + const def = agents.buildMemorizeAgent() + note(def.mode === "subagent", "memorize mode is subagent") + const rules = def.permissions + note(rules[0]?.action === "*" && rules[0]?.effect === "deny", "wildcard deny is first") + const allows = new Set(rules.filter((r) => r.effect === "allow").map((r) => r.action)) + const safeAllows = new Set(["read", "edit", "glob", "grep", "external_directory"]) + note([...allows].every((a) => safeAllows.has(a)), `allows ⊆ read/edit/glob/grep/external_directory (got ${[...allows].join(",")})`) + for (const t of ["read", "edit", "glob", "grep"]) note(allows.has(t), `allows ${t}`) + + // --- V2 tool sets --- + const tools = (await import(path.join(root, "dist", "src", "v2", "tools.js") + `?t=${Date.now()}`)) as typeof import("../src/v2/tools.js") + const names = tools.buildV2Tools().map((t) => t.name).sort() + for (const t of ["memory_read", "memory_search", "memory_list", "memory_add_note", "memory_reset", "memory_inspect", "memory_mode"]) { + note(names.includes(t), `v2 tool ${t} registered`) + } + } finally { + fs.rmSync(testRoot, { recursive: true, force: true }) + } + + if (failed > 0) { + console.error(`contract2: FAIL — ${failed} check(s) broken`) + process.exit(1) + } + console.log("contract2: OK — v2 host surface aligned") +} + +await main() diff --git a/src/index.ts b/src/index.ts index 2e678f2..c198829 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,6 +12,7 @@ import { beginPluginShutdown, isPluginShuttingDown, resetPluginLifecycle } from import { hostMcpStatus } from "./host-client.js" import { recordDiagnostic } from "./diagnostics.js" import { loadBundledAgentDefinitions, recordAgentConfig, resetAgentHealth } from "./agent-health.js" +import { setup as setupV2 } from "./v2/plugin.js" import type { PluginInput, PluginOptions } from "@opencode-ai/plugin" import path from "path" @@ -118,6 +119,9 @@ export function handleSessionDeleted( export default { id: "opencode-codex-memory", + // opencode2 entry point (V2 reads id + setup(), ignoring server()). + // Added additively: V1 hosts keep calling server() exactly as before. + setup: setupV2, async server(input: PluginInput, opts?: PluginOptions) { // A reload after dispose must be able to run the pipeline again. resetPluginLifecycle() diff --git a/src/v2/agents.ts b/src/v2/agents.ts new file mode 100644 index 0000000..fd21ad2 --- /dev/null +++ b/src/v2/agents.ts @@ -0,0 +1,198 @@ +/** + * opencode2 agent provisioning. + * + * V1 ships memorize/memorize-extract via the config hook (opencode.json + * `agent` map). V2 has no config hook, but agent.transform's update() creates + * a missing agent, so setup() ensures them here instead. + * + * Both agents ship for parity, with the V1 prompts verbatim. `memorize` does + * consolidation work; `memorize-extract` is hidden and unused — extraction + * runs through generate.text (inherently tool-less, no session, no agent), + * and V1 skips injecting unused agents for the same reason. Keeping the + * hidden definition preserves the health snapshot both agents report into. + */ +import path from "path" +import { memoryRoot } from "../paths.js" +import { pluginOptions } from "../options.js" +import { recordAgentConfig } from "../agent-health.js" + +export const MEMORIZE_AGENT_ID = "memorize" +export const MEMORIZE_EXTRACT_AGENT_ID = "memorize-extract" + +export const MEMORIZE_SYSTEM = + "You are a memory consolidation agent. Read the workspace diff file and update MEMORY.md, memory_summary.md, and skills/ under the memory workspace only. Do not read or edit project source files outside that memory root. Keep memory_summary.md under 10000 chars (2500 tokens). Prune stale entries. Do not access the network." + +export const MEMORIZE_EXTRACT_SYSTEM = + "You are a memory extraction agent. The session transcript is provided inline in the prompt. Extract raw_memory, rollout_summary, and rollout_slug as JSON. Exclude AGENTS.md/instruction content. Redact secrets." + +export const MEMORIZE_DESCRIPTION = "Memory consolidation agent (opencode-codex-memory)" +export const MEMORIZE_EXTRACT_DESCRIPTION = "Memory extraction agent (opencode-codex-memory)" + +export interface V2AgentDefinition { + description: string + mode: "subagent" + hidden?: boolean + system: string + permissions: { action: string; resource: string; effect: "allow" | "deny" | "ask" }[] +} + +/** V2-native memorize definition (V2 action names: edit covers write/patch). */ +export function buildMemorizeAgent(): V2AgentDefinition { return { + description: MEMORIZE_DESCRIPTION, + mode: "subagent", + system: MEMORIZE_SYSTEM, + permissions: [ + { action: "*", resource: "*", effect: "deny" }, + { action: "read", resource: "*", effect: "allow" }, + { action: "edit", resource: "*", effect: "allow" }, + { action: "glob", resource: "*", effect: "allow" }, + { action: "grep", resource: "*", effect: "allow" }, + // Memories live outside every project: without this grant the wildcard + // deny blocks consolidation from touching the memory workspace (same + // role as external_directory in the V1 definition). + { action: "external_directory", resource: path.join(memoryRoot(), "*"), effect: "allow" }, + ], + } +} + +/** + * Hidden extraction definition. Unused at runtime (extraction goes through + * generate.text), kept for parity with the V1 bundle and the health + * snapshot. deny-all: V2 has no StructuredOutput-capture concept, and the + * sessionless generate path needs no tools at all. + */ +export function buildMemorizeExtractAgent(): V2AgentDefinition { + return { + description: MEMORIZE_EXTRACT_DESCRIPTION, + mode: "subagent", + hidden: true, + system: MEMORIZE_EXTRACT_SYSTEM, + permissions: [{ action: "*", resource: "*", effect: "deny" }], + } +} + +interface AgentEditorLike { + get(id: string): { description?: string; mode?: string; system?: string; permissions?: unknown } | undefined + update(id: string, update: (agent: Record) => void): void +} + +/** + * V2 agent definition converted back to the V1 permission-map shape so the + * shared agent-health snapshot (surfaced by memory_inspect) keeps working. + */ +export function toV1AgentDefinition(def: V2AgentDefinition, agentId?: string): Record { + const permission: Record = {} + for (const rule of def.permissions) { + if (rule.action === "*") { + permission["*"] = rule.effect + continue + } + if (rule.action === "external_directory") { + const cur = (permission.external_directory ?? {}) as Record + cur[rule.resource] = rule.effect + permission.external_directory = cur + continue + } + if (rule.action === "edit") { + // V1 names write/patch separately from edit. + permission.edit = rule.effect + permission.write = rule.effect + continue + } + permission[rule.action] = rule.effect + } + if (agentId === MEMORIZE_EXTRACT_AGENT_ID) { + // The V1 bundle allows the synthetic StructuredOutput capture tool so + // json_schema extraction works; V2 needs no tools for the sessionless + // generate path, but health validates the V1 bundle semantics. + permission.StructuredOutput = "allow" + } + return { mode: def.mode, prompt: def.system, description: def.description, permission } +} + +export function shippedV1AgentForHealth(): Record { + return { + [MEMORIZE_AGENT_ID]: toV1AgentDefinition(buildMemorizeAgent(), MEMORIZE_AGENT_ID), + [MEMORIZE_EXTRACT_AGENT_ID]: toV1AgentDefinition(buildMemorizeExtractAgent(), MEMORIZE_EXTRACT_AGENT_ID), + } +} + +/** + * Ensure both sub-agents exist. A user-defined agent of the same name + * always wins (mirrors injectAgentDefinitions). Records health for + * memory_inspect in both cases. + */ +export async function ensureV2Agents(ctx: { + agent: { + transform(cb: (editor: AgentEditorLike) => void): Promise + get(input: unknown): Promise + } +}): Promise { + const shipped: [string, V2AgentDefinition][] = [ + [MEMORIZE_AGENT_ID, buildMemorizeAgent()], + [MEMORIZE_EXTRACT_AGENT_ID, buildMemorizeExtractAgent()], + ] + if (!pluginOptions.generate_memories) { + recordAgentConfig({ agent: {} }, false, shippedV1AgentForHealth()) + return + } + const effective: Record = {} + const missing: [string, V2AgentDefinition][] = [] + for (const [id, def] of shipped) { + let existing: unknown = null + try { + const res = (await ctx.agent.get({ agentID: id })) as { data?: unknown } | undefined + existing = res && typeof res === "object" && "data" in res ? (res as { data: unknown }).data : res + } catch { + existing = null + } + if (existing && typeof existing === "object") { + // Present (ours or a user override): never overwrite, just record health. + const cur = existing as Record + effective[id] = { + mode: cur.mode, + prompt: cur.system, + permission: v2PermissionsToV1Map(cur.permissions), + } + } else { + missing.push([id, def]) + } + } + if (missing.length > 0) { + await ctx.agent.transform((editor) => { + for (const [id, def] of missing) { + editor.update(id, (agent) => { + agent.description = def.description + agent.mode = def.mode + if (def.hidden !== undefined) agent.hidden = def.hidden + agent.system = def.system + agent.permissions = def.permissions.map((r) => ({ ...r })) + }) + } + }) + for (const [id, def] of missing) { + effective[id] = toV1AgentDefinition(def, id) + } + } + recordAgentConfig({ agent: effective }, true, shippedV1AgentForHealth()) +} + +function v2PermissionsToV1Map(permissions: unknown): Record { + const out: Record = {} + if (!Array.isArray(permissions)) return out + for (const rule of permissions as { action?: unknown; resource?: unknown; effect?: unknown }[]) { + if (typeof rule?.action !== "string") continue + if (rule.action === "*") { + out["*"] = rule.effect + continue + } + if (rule.action === "external_directory" && typeof rule.resource === "string") { + const cur = (out.external_directory ?? {}) as Record + cur[rule.resource] = rule.effect + out.external_directory = cur + continue + } + out[rule.action] = rule.effect + } + return out +} diff --git a/src/v2/index.ts b/src/v2/index.ts new file mode 100644 index 0000000..b78cde3 --- /dev/null +++ b/src/v2/index.ts @@ -0,0 +1,11 @@ +/** + * opencode2 entry point (re-exported through the package main for + * single-entry dual-host support: V1 reads server(), V2 reads id+setup()). + */ +import { Plugin } from "@opencode/plugin" +import { setup } from "./plugin.js" + +export default Plugin.define({ + id: "opencode-codex-memory", + setup, +}) diff --git a/src/v2/plugin.ts b/src/v2/plugin.ts new file mode 100644 index 0000000..64fb8be --- /dev/null +++ b/src/v2/plugin.ts @@ -0,0 +1,368 @@ +/** + * opencode2 plugin setup. + * + * The V1 pipeline (phase1/phase2/capture/llm/…) runs unchanged on top of the + * V1-client shim (./shim.ts). This module only translates V2 host surfaces + * into the same calls the V1 hooks made: + * + * - prompt hook → turn-start stamp + phase-1 pump (was chat.message) + * - context hook → memory injection (was system.transform) + citation + * record/strip (was text.complete/messages.transform) + * - tool.execute.before→ external-context pollution mark (unchanged name) + * - session.created → session-registry sighting (feeds V2 discovery) + * - execution.succeeded→ phase-1 pump (was session.status idle/session.idle) + * - agent.transform → memorize sub-agent provisioning (was config hook) + * - tool.transform → memory tool registration (was returned tool map) + * + * Known V2 adaptations (see docs/opencode2.md): sessions cannot be deleted + * (helpers are interrupted + released, rows remain as inert history); + * discovery is registry-based (no list API); citations are stripped from the + * model-bound transcript but remain in stored history; config/get-based + * model defaults are unavailable (set extract_model/consolidation_model). + */ +import { ensureMemoryLayout, buildMemorySystemPrompt, invalidateCache } from "../source.js" +import { stripCitations, extractCitedSessionIds } from "../citation.js" +import { MemoryStore } from "../store.js" +import { runPhase1 } from "../phase1.js" +import { runPhase2 } from "../phase2.js" +import { + setPluginInput, + cleanupOldSubSessions, + isMemorySubSession, + abortActiveSubSessions, +} from "../llm.js" +import { pluginOptions, clearConfigWarnings, resetPluginOptions } from "../options.js" +import { beginPluginShutdown, isPluginShuttingDown, resetPluginLifecycle } from "../lifecycle.js" +import { hostMcpStatus } from "../host-client.js" +import { recordDiagnostic } from "../diagnostics.js" +import { resetAgentHealth } from "../agent-health.js" +import { applyPluginOptions } from "../index.js" +import { + setV2Context, + buildV1ClientShim, + recordSessionSighting, + type V2Context, +} from "./shim.js" +import { ensureV2Agents } from "./agents.js" +import { buildV2Tools } from "./tools.js" +import { MemoryStatusRpc } from "./status-rpc.js" +import { readMemoryStatus } from "./status.js" + +let phase1InFlight = false +let shimClient: unknown = null +const backgroundTasks = new Set>() +const statusListeners = new Set<() => void>() + +function notifyStatusChanged(): void { + for (const notify of statusListeners) notify() +} + +function trackBackgroundTask(task: Promise): void { + const tracked = task.catch((err) => { + console.error("[opencode-codex-memory] background task error:", err) + }) + backgroundTasks.add(tracked) + void tracked.then(() => backgroundTasks.delete(tracked)) +} + +/** Test seam: wait for hook-launched work to settle. */ +export async function waitForV2BackgroundTasks(): Promise { + while (backgroundTasks.size > 0) { + await Promise.all([...backgroundTasks]) + } +} + +/** Test seam: reset module state between tests. */ +export function resetV2ModuleStateForTest(): void { + phase1InFlight = false + statusListeners.clear() + backgroundTasks.clear() + recordedCitations.clear() + seenTurnSessions.clear() + mcpStatusInFlight = null +} + +function getStore(): MemoryStore { + return new MemoryStore() +} + +// Citation blocks surface on every context call for as long as the message +// is in history (V2 has no pre-persist strip hook), so count each citation +// exactly once per message per process. +const recordedCitations = new Map>() +const MAX_TRACKED_PARTS = 500 + +function lruSet(map: Map, key: K, value: V, max: number): V { + map.delete(key) + map.set(key, value) + if (map.size > max) { + const oldest = map.keys().next().value + if (oldest !== undefined) map.delete(oldest) + } + return value +} + +export function takeNewV2Citations(partKey: string, ids: string[]): string[] { + const seen = recordedCitations.get(partKey) ?? new Set() + lruSet(recordedCitations, partKey, seen, MAX_TRACKED_PARTS) + const fresh = ids.filter((id) => !seen.has(id)) + for (const id of fresh) seen.add(id) + return fresh +} + +// One stamp+pump per session per process from the prompt hook. +const seenTurnSessions = new Map() +const MAX_TRACKED_TURN_SESSIONS = 1000 + +export function markV2TurnSeen(sessionId: string): boolean { + const first = seenTurnSessions.get(sessionId) + lruSet(seenTurnSessions, sessionId, first ?? Date.now(), MAX_TRACKED_TURN_SESSIONS) + return first === undefined +} + +let mcpStatusInFlight: Promise | null = null +const MCP_STATUS_TIMEOUT_MS = 1_000 + +async function mcpToolPrefixes(): Promise { + if (!shimClient) return null + if (!mcpStatusInFlight) { + mcpStatusInFlight = (async () => { + const controller = new AbortController() + let timer: ReturnType | undefined + try { + const res = await Promise.race([ + hostMcpStatus(shimClient as any, controller.signal), + new Promise((_, reject) => { + timer = setTimeout(() => { + controller.abort() + reject(new Error(`mcp status timed out after ${MCP_STATUS_TIMEOUT_MS}ms`)) + }, MCP_STATUS_TIMEOUT_MS) + }), + ]) + if (!res || (res as { error?: unknown }).error) return null + const servers = (res as { data?: unknown }).data + if (!servers || typeof servers !== "object" || Array.isArray(servers)) return null + const prefixes: string[] = [] + for (const [server, status] of Object.entries(servers as Record)) { + if (!status || typeof status !== "object" || typeof (status as { status?: unknown }).status !== "string") continue + prefixes.push(server.replace(/[^a-zA-Z0-9_-]/g, "_")) + } + return prefixes + } catch { + return null + } finally { + clearTimeout(timer) + mcpStatusInFlight = null + } + })() + } + return mcpStatusInFlight +} + +async function classifyExternalContextTool(toolName: string): Promise { + if (toolName === "websearch" || toolName === "webfetch") return true + const prefixes = await mcpToolPrefixes() + if (prefixes === null) return null + for (const prefix of prefixes) { + if (toolName.startsWith(`${prefix}_`) || toolName.startsWith(`mcp_${prefix}_`)) return true + } + return false +} + +function stampAndPump(sid: string): void { + try { + getStore().stampMemoryModeIfAbsent(sid, pluginOptions.generate_memories ? "enabled" : "disabled") + } catch (e) { + console.error("[opencode-codex-memory] stampMemoryModeIfAbsent failed:", e) + } + trackBackgroundTask(triggerPhase1(sid)) +} + +async function triggerPhase1(currentSessionId: string): Promise { + if (phase1InFlight || !pluginOptions.generate_memories || isPluginShuttingDown()) return + phase1InFlight = true + notifyStatusChanged() + try { + await runPhase1(getStore(), { + maxAgeDays: pluginOptions.max_rollout_age_days, + minIdleHours: pluginOptions.min_rollout_idle_hours, + maxClaimed: pluginOptions.max_rollouts_per_startup, + maxUnusedDays: pluginOptions.max_unused_days, + excludeSession: currentSessionId, + extractModel: pluginOptions.extract_model, + }) + } catch (err) { + console.error("[opencode-codex-memory] phase1 error:", err) + recordDiagnostic("error", "phase1", err instanceof Error ? err.message : String(err)) + } finally { + phase1InFlight = false + notifyStatusChanged() + } + trackBackgroundTask(triggerPhase2()) +} + +async function triggerPhase2(): Promise { + if (isPluginShuttingDown()) return + try { + const result = await runPhase2(getStore(), { + maxRaw: pluginOptions.max_raw_memories_for_consolidation, + maxUnusedDays: pluginOptions.max_unused_days, + extensionRetentionDays: 7, + consolidationModel: pluginOptions.consolidation_model, + codexInterop: pluginOptions.codex_interop, + claudeImport: pluginOptions.claude_import, + }) + if (result.status !== "already_running" && result.status !== "skipped_cooldown" && result.status !== "skipped_running") { + recordDiagnostic( + result.status === "succeeded" || result.status === "no_workspace_changes" ? "info" : "warn", + "phase2", + result.status, + ) + } + } catch (err) { + console.error("[opencode-codex-memory] phase2 error:", err) + recordDiagnostic("error", "phase2", err instanceof Error ? err.message : String(err)) + } finally { + notifyStatusChanged() + } +} + +export async function setup(ctx: V2Context): Promise<(() => void | Promise) | void> { + resetPluginLifecycle() + setV2Context(ctx) + shimClient = buildV1ClientShim() + setPluginInput({ client: shimClient } as any) + resetAgentHealth() + mcpStatusInFlight = null + clearConfigWarnings() + if (ctx.options) applyPluginOptions(ctx.options as Record) + else resetPluginOptions() + await ensureV2Agents(ctx as any) + + const statusRegistration = await ctx.rpc.register(MemoryStatusRpc, { + status: async () => readMemoryStatus(), + }) + const publishStatus = () => { + void statusRegistration.events.emit("changed", {}).catch((err) => { + console.warn("[opencode-codex-memory] status notification failed:", err) + }) + } + + const locationDirectory = (ctx.location as { directory?: string } | undefined)?.directory + + await ctx.tool.transform((editor: any) => { + for (const t of buildV2Tools()) editor.add(t) + }) + + await ctx.session.hook("prompt", (ev: any) => { + try { + const sid = ev?.sessionID + if (!sid || isMemorySubSession(sid)) return + recordSessionSighting(sid, { directory: locationDirectory ?? null }) + if (!markV2TurnSeen(sid)) return + stampAndPump(sid) + } catch (err) { + console.error("[opencode-codex-memory] v2 prompt hook error:", err) + } + }) + + await ctx.session.hook("context", (ev: any) => { + try { + const sid = ev?.sessionID + if (!sid || isMemorySubSession(sid)) return + // Citation feedback (write path): record usage and strip the block + // from the model-bound transcript. Stored history keeps the markup + // (V2 has no pre-persist hook); the per-message dedupe keeps counts + // exact within a process. + try { + for (const [i, msg] of (ev.messages ?? []).entries()) { + if (msg?.type !== "assistant" || !Array.isArray(msg.content)) continue + for (const part of msg.content) { + if (part?.type !== "text" || typeof part.text !== "string") continue + if (!part.text.includes("")) continue + try { + const ids = extractCitedSessionIds(part.text) + const fresh = takeNewV2Citations(`${sid}:${msg.id ?? i}`, ids) + if (fresh.length > 0) getStore().recordUsage(fresh) + } catch (e) { + console.error("[opencode-codex-memory] citation recording failed:", e) + } + part.text = stripCitations(part.text) + } + } + } catch (e) { + console.error("[opencode-codex-memory] v2 citation handling failed:", e) + } + // Read path: inject the memory summary block. + if (!pluginOptions.use_memories) return + ensureMemoryLayout() + const memoryPrompt = buildMemorySystemPrompt(pluginOptions.dedicated_tools) + if (memoryPrompt) { + ev.system.push({ type: "text", text: memoryPrompt }) + } + } catch (err) { + console.error("[opencode-codex-memory] v2 context hook error:", err) + } + }) + + await ctx.tool.hook("execute.before", async (ev: any) => { + try { + if (!pluginOptions.disable_on_external_context || !ev?.sessionID) return + if ((await classifyExternalContextTool(ev.tool)) !== true) return + getStore().markPolluted(ev.sessionID) + } catch (err) { + console.error("[opencode-codex-memory] v2 tool hook error:", err) + } + }) + + // Event loop: session.created feeds discovery; execution.succeeded pumps + // phase 1 the way V1's idle events did. + const eventAbort = new AbortController() + void (async () => { + while (!eventAbort.signal.aborted && !isPluginShuttingDown()) { + try { + for await (const raw of ctx.event.subscribe({ signal: eventAbort.signal })) { + const e = raw as { type?: string } & Record + try { + if (e.type === "session.created") { + if (e.sessionID && !isMemorySubSession(e.sessionID)) { + recordSessionSighting(e.sessionID, { + title: typeof e.title === "string" ? e.title : undefined, + directory: (e.location as { directory?: string } | undefined)?.directory ?? locationDirectory ?? null, + }) + } + } else if (e.type === "session.execution.succeeded" || e.type === "session.execution.ended") { + const sid = (e as { sessionID?: string }).sessionID + if (sid && !isMemorySubSession(sid)) { + recordSessionSighting(sid, { directory: locationDirectory ?? null }) + trackBackgroundTask(triggerPhase1(sid)) + } + } + } catch (err) { + console.error("[opencode-codex-memory] v2 event handling error:", err) + } + } + break + } catch (err) { + if (eventAbort.signal.aborted || isPluginShuttingDown()) break + console.error("[opencode-codex-memory] v2 event subscription error:", err) + await new Promise((r) => setTimeout(r, 5000)) + } + } + })().catch((err) => console.error("[opencode-codex-memory] v2 event loop error:", err)) + + // Bounded reseed before hooks observe traffic (mirrors server()). + await cleanupOldSubSessions() + statusListeners.add(publishStatus) + + return () => { + statusListeners.delete(publishStatus) + eventAbort.abort() + beginPluginShutdown() + setV2Context(null) + void abortActiveSubSessions().catch((err) => { + console.warn("[opencode-codex-memory] v2 dispose abort of sub-sessions failed:", err) + }) + invalidateCache() + } +} diff --git a/src/v2/shim.ts b/src/v2/shim.ts new file mode 100644 index 0000000..53c6560 --- /dev/null +++ b/src/v2/shim.ts @@ -0,0 +1,482 @@ +/** + * opencode2 host-compatibility shim. + * + * V2 intentionally reuses the V1 pipeline (phase1/phase2/capture/llm/store/… + * run byte-identical) by presenting a V1-shaped client façade backed by the + * V2 plugin context. Only genuinely missing V2 surfaces are adapted: + * + * - session list/discovery → process-local session registry (ctx has no + * list API; raw HTTP is 401 from inside plugins). Fed by session.created + * events + the prompt hook; pruned on observed NotFound. + * - session.prompt agent/system/model/format/variant → V2 create-time + * agent/model (via switchAgent/switchModel) + generate.text for the + * json_schema extraction path (V2 prompts carry text only). + * - session.messages → session.context with V1-shaped row adaptation. + * - session.delete → interrupt + released-set (V2 has no delete; the row + * remains as inert history). get() on a released id reports 404 so the + * V1 shutdown/liveness logic keeps working. + * - config.get → unavailable (V2 exposes no config API to plugins); callers + * fall back to session defaults, exactly like a V1 host without config. + * - provider.list → catalog.model.list adapted to the V1 catalog shape for + * reasoning-variant mapping. + * - mcp.status → mcp.list adapted to the V1 status map. + * + * Nothing in this file changes V1 behavior: V1 hosts never load it. + */ +import type { Plugin } from "@opencode/plugin" +import { memoryRoot } from "../paths.js" + +export type V2Context = Plugin.Context + +let v2ctx: V2Context | null = null + +export function setV2Context(ctx: V2Context | null): void { + v2ctx = ctx +} + +export function getV2Context(): V2Context | null { + return v2ctx +} + +function ctx(): V2Context { + if (!v2ctx) throw new Error("v2 context not initialized") + return v2ctx +} + +/** Unwrap {data} vs direct payloads (client shape varies by call). */ +function und(v: unknown): any { + const r = v as { data?: unknown } | null | undefined + if (r && typeof r === "object" && "data" in r) return (r as { data: unknown }).data + return v +} + +function isNotFoundError(e: unknown): boolean { + if (!e || typeof e !== "object") return String(e ?? "").includes("404") + const r = e as { _tag?: unknown; name?: unknown; message?: unknown; status?: unknown } + if (r.status === 404) return true + for (const f of [r._tag, r.name, r.message]) { + if (typeof f === "string" && /notfound|404/i.test(f)) return true + } + return false +} + +/** Sub-session ids released via delete(): report 404 from get(). */ +const releasedSubSessions = new Set() +const RELEASED_CAP = 500 + +function markReleased(id: string): void { + releasedSubSessions.add(id) + if (releasedSubSessions.size > RELEASED_CAP) { + const oldest = releasedSubSessions.values().next().value + if (oldest !== undefined) releasedSubSessions.delete(oldest) + } +} + +export function isReleasedSubSession(id: string): boolean { + return releasedSubSessions.has(id) +} + +// --------------------------------------------------------------------------- +// Session registry (V2 discovery replacement) +// --------------------------------------------------------------------------- + +export interface RegistryEntry { + id: string + title?: string + directory: string | null + parentID?: string | null + created: number + updated: number +} + +const registry = new Map() +const REGISTRY_CAP = 5000 + +export function recordSessionSighting( + id: string, + opts: { title?: string; directory?: string | null; parentID?: string | null; updated?: number } = {}, +): void { + const now = Date.now() + const prev = registry.get(id) + registry.set(id, { + id, + title: opts.title ?? prev?.title, + directory: opts.directory ?? prev?.directory ?? null, + parentID: opts.parentID ?? prev?.parentID, + created: prev?.created ?? now, + updated: opts.updated ?? now, + }) + if (registry.size > REGISTRY_CAP) { + let oldestKey: string | undefined + let oldest = Infinity + for (const [k, v] of registry) { + if (v.updated < oldest) { + oldest = v.updated + oldestKey = k + } + } + if (oldestKey !== undefined) registry.delete(oldestKey) + } + // Backfill parentID once (excludes subagent children like V1 roots=true). + if (registry.get(id)?.parentID === undefined) { + void (async () => { + try { + const info = und(await (ctx().session as any).get({ sessionID: id })) + if (info?.parentID !== undefined) { + const cur = registry.get(id) + if (cur) cur.parentID = info.parentID ?? null + } else { + const cur = registry.get(id) + if (cur && cur.parentID === undefined) cur.parentID = null + } + } catch { + // Best-effort backfill; a later liveness check prunes gone rows. + } + })() + } +} + +export function dropSessionFromRegistry(id: string): void { + registry.delete(id) +} + +/** Stable synthetic id for extraction helpers (see create below). */ +export const EXTRACT_STUB_SESSION_ID = "codex-memory-extract-stub" + +/** Test seam. */ +export function clearSessionRegistryForTest(): void { + registry.clear() + releasedSubSessions.clear() +} + +function registryRows(limit: number, cursor?: number, search?: string): RegistryEntry[] { + let rows = [...registry.values()] + if (cursor !== undefined) rows = rows.filter((r) => r.updated < cursor) + if (search) { + const q = search.toLowerCase() + rows = rows.filter( + (r) => r.id.toLowerCase().includes(q) || (r.title ?? "").toLowerCase().includes(q), + ) + } + rows.sort((a, b) => b.updated - a.updated) + return rows.slice(0, limit) +} + +// --------------------------------------------------------------------------- +// Shape adapters +// --------------------------------------------------------------------------- + +function joinTextParts(content: unknown): string { + if (!Array.isArray(content)) return "" + const out: string[] = [] + for (const p of content) { + if (p && typeof p === "object" && (p as { type?: unknown }).type === "text" && typeof (p as { text?: unknown }).text === "string") { + out.push((p as { text: string }).text) + } else if (typeof p === "string") { + out.push(p) + } + } + return out.join("\n") +} + +/** + * V2 context()/transcript messages → V1 session.messages rows + * ({info:{role}, parts:[...]}) consumed by capture.ts extractText. + */ +export function adaptV2Messages(msgs: unknown): Array<{ info?: { role?: string }; parts?: unknown[] }> { + if (!Array.isArray(msgs)) return [] + const rows: Array<{ info?: { role?: string }; parts?: unknown[] }> = [] + for (const m of msgs as any[]) { + if (!m || typeof m !== "object") continue + if (m.type === "user") { + rows.push({ info: { role: "user" }, parts: [{ type: "text", text: m.text }] }) + continue + } + if (m.type === "system") { + rows.push({ info: { role: "system" }, parts: [{ type: "system", text: m.text }] }) + continue + } + if (m.type === "assistant") { + const parts: unknown[] = [] + for (const p of m.content ?? []) { + if (!p || typeof p !== "object") continue + if (p.type === "text") parts.push({ type: "text", text: p.text }) + else if (p.type === "reasoning") parts.push({ type: "reasoning" }) + else if (p.type === "tool") { + // The codemode `execute` wrapper runs code that calls the real + // tools; expand its toolCalls so the transcript keeps V1's + // per-tool granularity ([tool: name] input/output). + const calls = (p.state as any)?.metadata?.toolCalls ?? (p as any)?.metadata?.toolCalls + if (p.name === "execute" && Array.isArray(calls) && calls.length > 0) { + const outputText = joinTextParts((p.state as any)?.content) + for (const c of calls) { + parts.push({ + type: "tool", + tool: c.tool ?? "execute", + state: { + input: c.input ?? (p.state as any)?.input, + ...(outputText ? { output: outputText } : {}), + }, + }) + } + } else { + const st = (p.state as any) ?? {} + const outputText = joinTextParts(st.content) + parts.push({ + type: "tool", + tool: p.name ?? "unknown", + state: { + ...(st.input !== undefined ? { input: st.input } : {}), + ...(outputText ? { output: outputText } : {}), + ...(typeof st.error === "string" ? { error: st.error } : {}), + }, + }) + } + } + } + rows.push({ info: { role: "assistant" }, parts }) + continue + } + // synthetic/skill/shell/compaction/…: keep visible text, if any. + if (typeof m.text === "string") { + rows.push({ info: { role: m.type }, parts: [{ type: "text", text: m.text }] }) + } else { + rows.push({ info: { role: m.type }, parts: [] }) + } + } + return rows +} + +/** V2 catalog.model.list → V1 provider-list shape for catalogVariantKeys. */ +export function adaptProviderCatalog(v2: unknown): unknown { + const items = und(v2) + const list: any[] = Array.isArray(items) ? items : (items as any)?.data ?? [] + const providers = new Map>() + for (const m of list) { + if (!m || typeof m !== "object") continue + const providerID = (m as any).providerID + const modelID = (m as any).modelID ?? (m as any).id + if (typeof providerID !== "string" || typeof modelID !== "string") continue + if (!providers.has(providerID)) providers.set(providerID, {}) + const variants: Record = {} + for (const v of (m as any).variants ?? []) { + if (v && typeof v === "object" && typeof (v as any).id === "string") { + variants[(v as any).id] = { ...(typeof (v as any).disabled === "boolean" ? { disabled: (v as any).disabled } : {}) } + } + } + ;(providers.get(providerID) as Record)[modelID] = { variants } + } + return { all: [...providers.entries()].map(([id, models]) => ({ id, models })) } +} + +/** V2 mcp.list → V1 mcp.status map shape. */ +export function adaptMcpStatus(v2: unknown): unknown { + const items = und(v2) + const list: any[] = Array.isArray(items) ? items : [] + const out: Record = {} + for (const s of list) { + if (!s || typeof s !== "object" || typeof (s as any).name !== "string") continue + const st = (s as any).status + out[(s as any).name] = { status: typeof st === "string" ? st : (st?.status ?? "unknown") } + } + return out +} + +function parseModelRef(ref: string): { providerID: string; modelID: string } | null { + const slash = ref.indexOf("/") + if (slash <= 0 || slash === ref.length - 1) return null + return { providerID: ref.slice(0, slash), modelID: ref.slice(slash + 1) } +} + +// --------------------------------------------------------------------------- +// The façade: V1-shaped client over the V2 context +// --------------------------------------------------------------------------- + +async function v2promptWithWait( + sessionID: string, + body: { agent: string; system?: string; model?: { providerID: string; modelID: string }; format?: unknown; variant?: string; parts: { type: string; text: string }[] }, + signal?: AbortSignal, +): Promise<{ error?: unknown; data?: unknown }> { + const c = ctx() + const text = body.parts.map((p) => p.text ?? "").join("\n") + // Structured-output extraction: V2 prompts carry text only, so run the + // turn through generate.text (inherently tool-less, like the V1 + // memorize-extract sandbox) with the system prompt prepended. The caller + // falls back to JSON text parsing (hostStructuredOutput finds nothing). + if (body.format) { + const prompt = body.system ? `${body.system}\n\n---\n\n${text}` : text + const parsed = body.model ? parseModelRef(`${body.model.providerID}/${body.model.modelID}`) : null + const gen = await (c as any).generate.text({ + prompt, + ...(parsed || body.variant + ? { + model: { + ...(parsed ? { providerID: parsed.providerID, id: parsed.modelID } : {}), + ...(body.variant ? { variant: body.variant } : {}), + }, + } + : {}), + }) + const outText = typeof gen?.text === "string" ? gen.text : JSON.stringify(gen) + return { data: { parts: [{ type: "text", text: outText }] } } + } + // Agentic turn (consolidation): the agent/model must be set at CREATE time + // in V2, so switch the fresh helper session first, then prompt + wait to + // preserve V1's "prompt resolves after the turn" semantics. + if (body.agent) { + await (c.session as any).switchAgent({ sessionID, agent: body.agent }) + } + if (body.model) { + await (c.session as any).switchModel({ + sessionID, + model: { + providerID: body.model.providerID, + id: body.model.modelID, + ...(body.variant ? { variant: body.variant } : {}), + }, + }) + } + const posted = await (c.session as any).prompt({ sessionID, text }) + const waitP = (c.session as any).wait({ sessionID }) + if (signal) { + if (signal.aborted) { + await (c.session as any).interrupt({ sessionID }).catch(() => {}) + throw new Error("sub-agent prompt cancelled") + } + await Promise.race([ + waitP, + new Promise((_, reject) => { + signal.addEventListener("abort", () => reject(new Error("sub-agent prompt cancelled")), { once: true }) + }), + ]).catch(async (e) => { + await (c.session as any).interrupt({ sessionID }).catch(() => {}) + throw e + }) + } else { + await waitP + } + return { data: { posted } } +} + +/** Build the V1-shaped client. Passed to setPluginInput() by V2 setup(). */ +export function buildV1ClientShim(): unknown { + const session = { + create: async (opts: { query?: { directory?: string }; body?: { title?: string; metadata?: Record } }) => { + try { + // Extraction turns run through generate.text (see prompt below) and + // never touch a session, so hand out a stable synthetic id instead + // of creating a server row per extraction (V2 has no session + // delete; without this each extraction would litter one dead + // `codex-memory-extract-*` session). Skip/tracking logic keys off + // the id string only, so behavior is unchanged. + if (opts?.body?.title?.startsWith("codex-memory-extract-")) { + releasedSubSessions.delete(EXTRACT_STUB_SESSION_ID) + return { data: { id: EXTRACT_STUB_SESSION_ID } } + } + const res = await (ctx().session as any).create({ + ...(opts?.body?.title ? { title: opts.body.title } : {}), + ...(opts?.body?.metadata ? { metadata: opts.body.metadata } : {}), + location: { directory: opts?.query?.directory ?? memoryRoot() }, + }) + return { data: { id: und(res)?.id } } + } catch (e) { + return { error: e } + } + }, + prompt: async (opts: { path: { id: string }; body: any; signal?: AbortSignal }) => { + try { + return await v2promptWithWait(opts.path.id, opts.body, opts.signal) + } catch (e) { + return { error: e } + } + }, + messages: async (opts: { path: { id: string } }) => { + try { + if (isReleasedSubSession(opts.path.id)) throw Object.assign(new Error("SessionNotFound"), { _tag: "SessionNotFoundError" }) + const rows = und(await (ctx().session as any).context({ sessionID: opts.path.id })) + return { data: adaptV2Messages(rows) } + } catch (e) { + return { error: e } + } + }, + delete: async (opts: { path: { id: string } }) => { + // V2 has no session delete: stop the turn and treat the id as + // released so get()-based checks report 404 from here on. + try { + await (ctx().session as any).interrupt({ sessionID: opts.path.id }).catch(() => {}) + } finally { + markReleased(opts.path.id) + } + return {} + }, + get: async (opts: { path: { id: string } }) => { + try { + if (isReleasedSubSession(opts.path.id)) { + return { response: { status: 404 }, error: { _tag: "SessionNotFoundError" } } + } + const info = und(await (ctx().session as any).get({ sessionID: opts.path.id })) + return { data: info } + } catch (e) { + if (isNotFoundError(e)) return { response: { status: 404 }, error: e } + return { error: e } + } + }, + abort: async (opts: { path: { id: string } }) => { + try { + await (ctx().session as any).interrupt({ sessionID: opts.path.id }) + } catch { + // Best-effort, mirrors V1. + } + return {} + }, + } + const config = { + get: async () => ({ error: { message: "config unavailable to V2 plugins; using session defaults" } }), + } + const provider = { + list: async () => { + try { + const res = await (ctx() as any).catalog.model.list() + return { data: adaptProviderCatalog(res) } + } catch (e) { + return { error: e } + } + }, + } + const mcp = { + status: async () => { + try { + const res = await (ctx().mcp as any).list() + return { data: adaptMcpStatus(res) } + } catch (e) { + return { error: e } + } + }, + } + const _client = { + get: async (opts: { url: string; query?: Record }) => { + if (opts.url === "/experimental/session") { + const q = opts.query ?? {} + const rows = registryRows( + typeof q.limit === "number" ? q.limit : 5000, + typeof q.cursor === "number" ? q.cursor : undefined, + typeof q.search === "string" ? q.search : undefined, + ) + return { + data: rows.map((r) => ({ + id: r.id, + ...(r.parentID ? { parentID: r.parentID } : {}), + ...(r.title ? { title: r.title } : {}), + time: { created: r.created, updated: r.updated }, + ...(r.directory ? { directory: r.directory } : {}), + })), + } + } + if (opts.url === "/provider") { + return provider.list() + } + return { error: { message: `unsupported shim route ${opts.url}` } } + }, + } + return { session, config, provider, mcp, _client } +} diff --git a/src/v2/status-rpc.ts b/src/v2/status-rpc.ts new file mode 100644 index 0000000..5007927 --- /dev/null +++ b/src/v2/status-rpc.ts @@ -0,0 +1,103 @@ +/** + * Shared server↔TUI wire contract for the memory sidebar status. + * + * Dependency-free on purpose: the TUI bundle runs in the CLI sandbox, where + * only `@opencode/plugin/tui` (+ rendering peers) is guaranteed to resolve. + * `Rpc.define` is a runtime passthrough (validation only), so a plain object + * with JSON Schema nodes is an equivalent portable definition. + */ +export const MEMORY_STATUS_ACTIVITIES = [ + "idle", + "extracting", + "consolidating", + "retrying", + "error", + "read_only", + "disabled", + "stopping", +] as const + +export type MemoryStatusActivity = (typeof MEMORY_STATUS_ACTIVITIES)[number] + +export interface MemoryStatus { + activity: MemoryStatusActivity + useMemories: boolean + generateMemories: boolean + extractModel: string | null + consolidationModel: string | null + codexImport: boolean + lastSuccessAt: number | null + retryAt: number | null + warnings: string[] +} + +export const MemoryStatusRpc = { + id: "opencode-codex-memory", + methods: { + status: { + input: { type: "object", properties: {}, additionalProperties: false }, + output: { + type: "object", + properties: { + activity: { type: "string", enum: [...MEMORY_STATUS_ACTIVITIES] }, + useMemories: { type: "boolean" }, + generateMemories: { type: "boolean" }, + extractModel: { type: ["string", "null"] }, + consolidationModel: { type: ["string", "null"] }, + codexImport: { type: "boolean" }, + lastSuccessAt: { type: ["number", "null"] }, + retryAt: { type: ["number", "null"] }, + warnings: { type: "array", items: { type: "string" } }, + }, + required: [ + "activity", + "useMemories", + "generateMemories", + "extractModel", + "consolidationModel", + "codexImport", + "lastSuccessAt", + "retryAt", + "warnings", + ], + additionalProperties: false, + }, + }, + }, + events: { + changed: { schema: { type: "object", properties: {}, additionalProperties: false } }, + }, +} as const + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value) +} + +/** Runtime guard for the untyped RPC client result (no zod in the TUI bundle). */ +export function isMemoryStatus(value: unknown): value is MemoryStatus { + if (!isRecord(value)) return false + if ( + typeof value.activity !== "string" || + !(MEMORY_STATUS_ACTIVITIES as readonly string[]).includes(value.activity) + ) { + return false + } + for (const key of ["useMemories", "generateMemories", "codexImport"] as const) { + if (typeof value[key] !== "boolean") return false + } + for (const key of ["extractModel", "consolidationModel", "lastSuccessAt", "retryAt"] as const) { + const v = value[key] + if (v !== null && typeof v !== (key === "extractModel" || key === "consolidationModel" ? "string" : "number")) { + return false + } + } + return ( + Array.isArray(value.warnings) && value.warnings.every((w): w is string => typeof w === "string") + ) +} + +/** Throwing parser for tests and call sites that want a typed value. */ +export function parseMemoryStatus(value: unknown): MemoryStatus { + if (!isMemoryStatus(value)) throw new Error("invalid memory status payload") + return value +} diff --git a/src/v2/status.ts b/src/v2/status.ts new file mode 100644 index 0000000..54642c0 --- /dev/null +++ b/src/v2/status.ts @@ -0,0 +1,55 @@ +import { MemoryStore } from "../store.js" +import { pluginOptions, getConfigWarnings } from "../options.js" +import { getAgentHealth } from "../agent-health.js" +import { isPhase2InFlight } from "../phase2.js" +import { isPluginShuttingDown } from "../lifecycle.js" +import { activeProviderCapacityBackoffs } from "../ratelimit.js" +import { resolveCodexInterop } from "../codex-interop.js" +import type { MemoryStatus } from "./status-rpc.js" + +/** Read the same snapshots as memory_inspect; never claim or advance a job. */ +export function readMemoryStatus(): MemoryStatus { + const store = new MemoryStore() + const phase1 = store.stage1JobSnapshot() + const phase2 = store.phase2JobSnapshot() + const options = pluginOptions + const now = Date.now() + const retryTimes = [ + ...activeProviderCapacityBackoffs().map((backoff) => backoff.retry_at), + ...phase1.recent_errors.map((error) => error.retry_at), + phase2?.retry_at, + ].filter((time): time is number => time != null && time * 1000 > now) + const retryAt = retryTimes.length ? Math.min(...retryTimes) * 1000 : null + const warnings = [...getConfigWarnings()] + const health = getAgentHealth() + if (options.generate_memories && health.observed) { + // V2 extraction is sessionless; only the consolidator agent is used. + warnings.push(...health.agents.memorize.issues.map((issue) => `memorize: ${issue}`)) + } + if (phase2?.last_error) warnings.push("Consolidation failed; see memory_inspect for details.") + if (phase1.by_failure_class.other_exhausted > 0) warnings.push("Some extraction jobs exhausted their retries.") + if (phase1.by_failure_class.provider_capacity > 0) warnings.push("Some extraction jobs hit provider capacity limits.") + const codexImport = options.codex_interop.import && resolveCodexInterop(options.codex_interop) !== null + if (options.codex_interop.import && !codexImport) warnings.push("Codex import is misconfigured.") + + let activity: MemoryStatus["activity"] = "idle" + if (isPluginShuttingDown()) activity = "stopping" + else if (isPhase2InFlight() || phase2?.status === "running") activity = "consolidating" + else if ((phase1.by_status.running ?? 0) > 0) activity = "extracting" + else if (!options.generate_memories) activity = options.use_memories ? "read_only" : "disabled" + else if (retryAt !== null) activity = "retrying" + else if (warnings.length > 0) activity = "error" + + return { + activity, + useMemories: options.use_memories, + generateMemories: options.generate_memories, + extractModel: options.extract_model ?? null, + consolidationModel: options.consolidation_model ?? null, + codexImport, + // finished_at on a failed attempt is NOT a successful consolidation. + lastSuccessAt: phase2?.success_finished_at != null ? phase2.success_finished_at * 1000 : null, + retryAt, + warnings, + } +} diff --git a/src/v2/tools.ts b/src/v2/tools.ts new file mode 100644 index 0000000..30b3cea --- /dev/null +++ b/src/v2/tools.ts @@ -0,0 +1,78 @@ +/** + * opencode2 tool registration. + * + * The memory tools' logic lives in tools/*.ts (V1 tool() definitions) and is + * reused verbatim: each V1 definition already bundles {description, args + * (zod raw shape), execute}. V2 accepts any StandardSchema as input, which + * zod v4 satisfies natively, so the adapter just re-wraps the same validate + * + execute path and maps the result shape: + * V1 string | {output, metadata} → V2 {content, metadata} + * No V1 file is touched and behavior is identical by construction. + */ +import { z } from "zod" +import { memory_read, memory_search, memory_list, memory_add_note } from "../../tools/memory.js" +import { memory_reset, memory_inspect, memory_mode } from "../../tools/control.js" +import { pluginOptions } from "../options.js" + +interface V1Tool { + description: string + args: Record + execute: (args: any, ctx: any) => Promise +} + +interface V2ToolDefinition { + name: string + description: string + input: z.ZodTypeAny + execute: (input: any, ctx: { sessionID: string; messageID: string; agent: string }) => Promise<{ content: string | unknown[]; metadata?: unknown }> +} + +function adaptTool(name: string, v1: V1Tool): V2ToolDefinition { + return { + name, + description: v1.description, + input: z.object(v1.args), + async execute(input: any, tctx: { sessionID: string; messageID: string; agent: string }) { + // V1 execute ctx ({sessionID, messageID, agent, directory, worktree, + // abort, metadata(), ask()}). Only sessionID is consumed (add_note, + // memory_mode); the rest is a faithful shim. + const v1ctx = { + sessionID: tctx.sessionID, + messageID: tctx.messageID, + agent: tctx.agent, + directory: "", + worktree: "", + abort: new AbortController().signal, + metadata: () => {}, + ask: async () => {}, + } + const res = await v1.execute(input, v1ctx) + if (typeof res === "string") return { content: res } + return { content: res.output ?? "", ...(res.metadata !== undefined ? { metadata: res.metadata } : {}) } + }, + } +} + +const ALL_MEMORY_TOOLS: [string, V1Tool][] = [ + ["memory_read", memory_read as unknown as V1Tool], + ["memory_search", memory_search as unknown as V1Tool], + ["memory_list", memory_list as unknown as V1Tool], + ["memory_add_note", memory_add_note as unknown as V1Tool], + ["memory_reset", memory_reset as unknown as V1Tool], + ["memory_inspect", memory_inspect as unknown as V1Tool], + ["memory_mode", memory_mode as unknown as V1Tool], +] + +const CONTROL_ONLY = new Set(["memory_reset", "memory_inspect", "memory_mode"]) + +/** + * Same gating as the V1 entry: the read/search/list/add-note tools require + * BOTH use_memories and dedicated_tools (codex MemoriesExtension); the + * control tools are always available. + */ +export function buildV2Tools(): V2ToolDefinition[] { + const full = pluginOptions.use_memories && pluginOptions.dedicated_tools + return ALL_MEMORY_TOOLS.filter(([name]) => full || CONTROL_ONLY.has(name)).map(([name, v1]) => + adaptTool(name, v1), + ) +} diff --git a/src/v2/tui.tsx b/src/v2/tui.tsx new file mode 100644 index 0000000..dadc81f --- /dev/null +++ b/src/v2/tui.tsx @@ -0,0 +1,195 @@ +import { Plugin } from "@opencode/plugin/tui" +import { createSignal, onCleanup } from "solid-js" +import { MemoryStatusRpc, isMemoryStatus, type MemoryStatus } from "./status-rpc.js" + +const labels: Record = { + idle: "Idle", + extracting: "Extracting", + consolidating: "Consolidating", + retrying: "Waiting to retry", + error: "Needs attention", + read_only: "Read only", + disabled: "Disabled", + stopping: "Stopping", +} + +type TuiContext = Parameters[0]["setup"]>[0] +type RpcClient = ReturnType + +function elapsed(time: number | null | undefined, now: number): string { + if (time == null) return "—" + const minutes = Math.max(0, Math.floor((now - time) / 60_000)) + if (minutes === 0) return "just now" + if (minutes < 60) return `${minutes}m ago` + if (minutes < 1440) return `${Math.floor(minutes / 60)}h ago` + return `${Math.floor(minutes / 1440)}d ago` +} + +/** + * Dual-arity slot registration. Early V2 previews exposed + * `ui.slot(name, render)`; current previews take a single options object. + * Branch on arity so either host works. + */ +function registerSlot(context: TuiContext, name: string, render: (input: any) => unknown): () => void { + const slot = context.ui.slot as unknown as (...args: unknown[]) => unknown + const claim = + slot.length <= 1 ? { append: name, render } : undefined + const dispose = claim ? slot(claim) : (slot as (n: string, r: unknown) => unknown)(name, render) + return typeof dispose === "function" ? (dispose as () => void) : () => {} +} + +/** + * Defensive theme lookup. Current previews expose a nested theme + * (`text.feedback.error.default`); earlier ones used flat keys. Resolve to a + * leaf color, tolerating either shape. + */ +function themeColor(theme: unknown, ...paths: readonly (readonly string[])[]): any { + for (const path of paths) { + let cursor: unknown = theme + for (const key of path) { + if (cursor === null || typeof cursor !== "object") { + cursor = undefined + break + } + cursor = (cursor as Record)[key] + } + if (cursor !== null && typeof cursor === "object" && "default" in (cursor as Record)) { + cursor = (cursor as Record).default + } + if (cursor !== undefined && cursor !== null) return cursor + } + return undefined +} + +async function fetchStatus(rpc: RpcClient, context: TuiContext): Promise { + const result = await rpc.status( + {}, + { + location: context.location ?? context.data.location.default(), + signal: AbortSignal.timeout(5_000), + }, + ) + // The RPC client is untyped for plain JSON-schema definitions. + if (!isMemoryStatus(result)) throw new Error("invalid memory status payload") + return result +} + +function formatDetails(current: MemoryStatus): string { + return [ + `Status: ${labels[current.activity]}`, + "Scope: Global", + `Use memories: ${current.useMemories ? "Enabled" : "Disabled"}`, + `Generate memories: ${current.generateMemories ? "Enabled" : "Disabled"}`, + `Extraction: ${current.extractModel ?? "Host default"}`, + `Consolidation: ${current.consolidationModel ?? "Host default"}`, + `Codex import: ${current.codexImport ? "Enabled" : "Disabled"}`, + `Last successful consolidation: ${current.lastSuccessAt == null ? "Not recorded for the latest attempt" : new Date(current.lastSuccessAt).toLocaleString()}`, + ...(current.retryAt == null ? [] : [`Retry eligible: ${new Date(current.retryAt).toLocaleString()}`]), + ...current.warnings, + "", + "Use memory_inspect for full diagnostics.", + ].join("\n") +} + +function StatusPanel(context: TuiContext) { + const rpc = context.client.rpc(MemoryStatusRpc) + const [status, setStatus] = createSignal() + const [unavailable, setUnavailable] = createSignal(false) + const [now, setNow] = createSignal(Date.now()) + + const refresh = async () => { + try { + setStatus(await fetchStatus(rpc, context)) + setUnavailable(false) + } catch { + setUnavailable(true) + } finally { + setNow(Date.now()) + } + } + + const unsubscribe = rpc.events.on("changed", () => void refresh()) + // Reconcile missed events, cross-process jobs, and relative timestamps. + const timer = setInterval(() => void refresh(), 5_000) + onCleanup(() => { + clearInterval(timer) + unsubscribe() + }) + void refresh() + + const title = () => (unavailable() ? "Unavailable" : status() ? labels[status()!.activity] : "Loading…") + const color = () => { + if (unavailable() || status()?.activity === "error") { + return themeColor(context.theme, ["text", "feedback", "error"], ["text"]) + } + if (status()?.activity === "retrying") { + return themeColor(context.theme, ["text", "feedback", "warning"], ["text"]) + } + if (status()?.activity === "extracting" || status()?.activity === "consolidating") { + return themeColor(context.theme, ["text", "status", "running"], ["text"]) + } + return themeColor(context.theme, ["text", "subdued"], ["textMuted"], ["text"]) + } + const muted = () => themeColor(context.theme, ["text", "subdued"], ["textMuted"], ["text"]) + const heading = () => themeColor(context.theme, ["text", "default"], ["text"]) + + // No : its empty placeholder is a bare text node under , + // which the renderer rejects. Unconditional lines with placeholders instead. + const scopeLine = () => " Scope Global" + const successLine = () => ` Last success ${status() ? elapsed(status()?.lastSuccessAt, now()) : "…"}` as string + const importLine = () => + ` Codex import ${status() ? (status()!.codexImport ? "Enabled" : "Disabled") : "…"}` as string + + return ( + + Memory + ● {title()} + {scopeLine()} + {successLine()} + {importLine()} + {" /memory-status"} + + ) +} + +function KeymapLayer(context: TuiContext) { + // keymap.layer must be invoked from a Solid component scope: its cleanup is + // owned by this component and released automatically on unmount. + context.keymap.layer(() => ({ + mode: "global", + commands: [ + { + id: "opencode-codex-memory.status", + title: "Show memory status", + group: "Memory", + palette: true, + slash: { name: "memory-status" }, + run: async () => { + const rpc = context.client.rpc(MemoryStatusRpc) + let message: string + try { + message = formatDetails(await fetchStatus(rpc, context)) + } catch { + message = "Memory status is unavailable. Check that the server memory plugin is enabled and connected." + } + await context.ui.dialog.alert({ title: "Memory status", message }) + }, + }, + ], + })) + return null +} + +export default Plugin.define({ + id: "opencode-codex-memory.tui", + setup(context) { + // setup() itself must stay free of Solid-scoped APIs: only slot claims + // here, everything reactive lives in the slot components above. + const offSidebar = registerSlot(context, "sidebar.content", () => StatusPanel(context)) + const offApp = registerSlot(context, "app", () => KeymapLayer(context)) + return () => { + offSidebar() + offApp() + } + }, +}) diff --git a/tests/v2-agents.test.ts b/tests/v2-agents.test.ts new file mode 100644 index 0000000..ad8c3d3 --- /dev/null +++ b/tests/v2-agents.test.ts @@ -0,0 +1,137 @@ +import { describe, it, expect, afterEach } from "bun:test" +import fs from "fs" +import path from "path" +import { buildMemorizeAgent, buildMemorizeExtractAgent, ensureV2Agents, toV1AgentDefinition, MEMORIZE_SYSTEM, MEMORIZE_EXTRACT_SYSTEM } from "../src/v2/agents.js" +import { getAgentHealth, resetAgentHealth } from "../src/agent-health.js" +import { resetPluginOptions } from "../src/options.js" +import { applyPluginOptions } from "../src/index.js" + +const OPENCODE_JSON = path.join(import.meta.dirname, "..", "opencode.json") +const SHIPPED_V2 = (JSON.parse(fs.readFileSync(OPENCODE_JSON, "utf8")).agents ?? {}) as Record +const ALLOWED_V2_ACTIONS = new Set(["read", "edit", "glob", "grep", "external_directory"]) + +function fakeAgentCtx(existing: Record = {}) { + const updates: { id: string; applied: Record }[] = [] + const removed: string[] = [] + return { + updates, + removed, + ctx: { + agent: { + get: async (input: { agentID: string }) => { + if (existing[input.agentID]) return { data: existing[input.agentID] } + throw new Error("Agent not found: " + input.agentID) + }, + transform: async (cb: (editor: any) => void) => { + const editor = { + get: (id: string) => existing[id], + update: (id: string, fn: (a: Record) => void) => { + const cur: Record = { ...(existing[id] ?? { id, name: id }) } + fn(cur) + updates.push({ id, applied: cur }) + }, + remove: (id: string) => { + removed.push(id) + }, + } + cb(editor) + }, + }, + }, + } +} + +afterEach(() => { + resetAgentHealth() + resetPluginOptions() +}) + +describe("v2 agent definitions (opencode.json agents)", () => { + it("ships both agents in V2 form (extract is hidden: extraction uses generate.text)", () => { + expect(Object.keys(SHIPPED_V2).sort()).toEqual(["memorize", "memorize-extract"]) + expect(SHIPPED_V2["memorize-extract"].hidden).toBe(true) + expect(SHIPPED_V2["memorize-extract"].system).toBe(MEMORIZE_EXTRACT_SYSTEM) + }) + + it("memorize uses a deny-first allowlist with V2 action names", () => { + const def = SHIPPED_V2.memorize + expect(def.mode).toBe("subagent") + expect(typeof def.system).toBe("string") + expect(def.system).toBe(MEMORIZE_SYSTEM) + const rules = def.permissions as { action: string; resource: string; effect: string }[] + expect(rules[0]).toEqual({ action: "*", resource: "*", effect: "deny" }) + for (const rule of rules) { + if (rule.effect === "allow") { + expect(ALLOWED_V2_ACTIONS.has(rule.action), `unexpected allowed action ${rule.action}`).toBe(true) + } + } + const allows = new Set(rules.filter((r) => r.effect === "allow").map((r) => r.action)) + for (const tool of ["read", "edit", "glob", "grep"]) { + expect(allows.has(tool), `missing allow for ${tool}`).toBe(true) + } + // V2 folds write/patch into edit; shell/subagent/network tools stay denied. + expect(allows.has("write")).toBe(false) + expect(allows.has("shell")).toBe(false) + expect(allows.has("subagent")).toBe(false) + }) + + it("built memorize agent adds the memory-root external_directory grant", () => { + const { memoryRoot } = require("../src/paths.js") + const def = buildMemorizeAgent() + expect(def.system).toBe(SHIPPED_V2.memorize.system) + const grant = def.permissions.find((r) => r.action === "external_directory") + expect(grant).toEqual({ action: "external_directory", resource: path.join(memoryRoot(), "*"), effect: "allow" }) + }) + + it("built extract agent is hidden and deny-all", () => { + const def = buildMemorizeExtractAgent() + expect(def.hidden).toBe(true) + expect(def.mode).toBe("subagent") + expect(def.system).toBe(SHIPPED_V2["memorize-extract"].system) + expect(def.permissions).toEqual([{ action: "*", resource: "*", effect: "deny" }]) + }) +}) + +describe("ensureV2Agents", () => { + it("creates both agents when absent and records shipped health", async () => { + const f = fakeAgentCtx() + await ensureV2Agents(f.ctx as any) + expect(f.updates.map((u) => u.id)).toEqual(["memorize", "memorize-extract"]) + const applied = f.updates[0].applied as any + expect(applied.mode).toBe("subagent") + expect(applied.system).toBe(MEMORIZE_SYSTEM) + expect(f.updates[1].applied).toMatchObject({ mode: "subagent", hidden: true }) + expect(getAgentHealth().agents.memorize).toMatchObject({ source: "shipped", healthy: true, issues: [] }) + expect(getAgentHealth().agents["memorize-extract"]).toMatchObject({ source: "shipped", healthy: true, issues: [] }) + }) + + it("leaves a user-defined memorize untouched and records override health", async () => { + const userDef = { id: "memorize", mode: "subagent", system: "custom", permissions: [{ action: "*", resource: "*", effect: "allow" }] } + const f = fakeAgentCtx({ memorize: userDef }) + await ensureV2Agents(f.ctx as any) + // Only the absent extract agent is created; the override is preserved. + expect(f.updates.map((u) => u.id)).toEqual(["memorize-extract"]) + const health = getAgentHealth() + expect(health.agents.memorize.source).toBe("user_override") + expect(health.agents.memorize.healthy).toBe(false) + }) + + it("skips provisioning when generation is off", async () => { + applyPluginOptions({ generate_memories: false }) + const f = fakeAgentCtx() + await ensureV2Agents(f.ctx as any) + expect(f.updates).toEqual([]) + expect(getAgentHealth().generationEnabled).toBe(false) + }) + + it("V1-health conversion maps edit to edit+write", () => { + const v1 = toV1AgentDefinition(buildMemorizeAgent()) as any + expect(v1.mode).toBe("subagent") + expect(v1.permission["*"]).toBe("deny") + expect(v1.permission.edit).toBe("allow") + expect(v1.permission.write).toBe("allow") + expect(v1.permission.read).toBe("allow") + expect(v1.permission.glob).toBe("allow") + expect(v1.permission.grep).toBe("allow") + }) +}) diff --git a/tests/v2-pipeline.test.ts b/tests/v2-pipeline.test.ts new file mode 100644 index 0000000..aaf1860 --- /dev/null +++ b/tests/v2-pipeline.test.ts @@ -0,0 +1,144 @@ +import { afterEach, beforeEach, describe, expect, it } from "bun:test" +import fs from "fs" +import os from "os" +import path from "path" +import { closeDb } from "../src/db.js" +import { resetDiscoveryCacheForTest } from "../src/capture.js" +import { buildMemorySystemPrompt } from "../src/source.js" +import { DEFAULT_PHASE1_OPTIONS, runPhase1 } from "../src/phase1.js" +import { DEFAULT_PHASE2_OPTIONS, runPhase2 } from "../src/phase2.js" +import { resetPluginLifecycle } from "../src/lifecycle.js" +import { setPluginInput } from "../src/llm.js" +import { MemoryStore } from "../src/store.js" +import { setV2Context, buildV1ClientShim, recordSessionSighting, clearSessionRegistryForTest } from "../src/v2/shim.js" + +const TEST_ROOT = path.join(os.tmpdir(), `ocm-v2pipeline-${process.pid}-${Date.now()}`) +const SESSION_ID = "ses_v2pipeline" + +beforeEach(() => { + closeDb() + resetPluginLifecycle() + resetDiscoveryCacheForTest() + clearSessionRegistryForTest() + fs.mkdirSync(TEST_ROOT, { recursive: true }) + process.env.OPENCODE_CODEX_MEMORY_TEST_ROOT = TEST_ROOT +}) + +afterEach(() => { + closeDb() + resetPluginLifecycle() + resetDiscoveryCacheForTest() + clearSessionRegistryForTest() + setV2Context(null) + setPluginInput({ client: undefined } as any) + delete process.env.OPENCODE_CODEX_MEMORY_TEST_ROOT + fs.rmSync(TEST_ROOT, { recursive: true, force: true }) +}) + +describe("v2 fake-context write pipeline", () => { + it("extracts via generate.text, consolidates via helper session, and injects", async () => { + const updatedAt = Date.now() - 7 * 60 * 60 * 1000 + const created: string[] = [] + const switched: { agent?: string; model?: unknown }[] = [] + const generated: unknown[] = [] + const interrupted: string[] = [] + const memoryDir = path.join(TEST_ROOT, "memories") + + const ctx: any = { + location: { directory: "/project" }, + options: {}, + session: { + create: async (input: { title?: string }) => { + const id = input.title?.includes("extract") ? "sub-extract" : "sub-consolidate" + created.push(id) + return { data: { id } } + }, + switchAgent: async (input: { agent: string }) => { + switched.push({ agent: input.agent }) + }, + switchModel: async (input: { model: unknown }) => { + switched.push({ model: input.model }) + }, + prompt: async (input: { sessionID: string; text: string }) => { + if (input.sessionID === "sub-consolidate") { + fs.writeFileSync(path.join(memoryDir, "MEMORY.md"), "# MEMORY.md\n\n- CSV parser uses strict typed rows.\n") + fs.writeFileSync(path.join(memoryDir, "memory_summary.md"), "v1\n\n- CSV parser uses strict typed rows.\n") + } + return { id: "msg_1" } + }, + wait: async () => {}, + interrupt: async (input: { sessionID: string }) => { + interrupted.push(input.sessionID) + return { interrupted: true } + }, + get: async (input: { sessionID: string }) => { + if (input.sessionID.startsWith("sub-")) throw { _tag: "SessionNotFoundError" } + return { id: input.sessionID, parentID: null } + }, + context: async (input: { sessionID: string }) => { + if (input.sessionID !== SESSION_ID) return [] + return [ + { id: "u1", time: { created: 1 }, text: "Use the durable CSV parser convention.", type: "user" }, + { + id: "a1", + time: { created: 2 }, + type: "assistant", + agent: "build", + model: { id: "m", providerID: "p" }, + content: [{ type: "text", text: "Implemented the parser with strict typed rows." }], + }, + ] + }, + }, + generate: { + text: async (input: { prompt: string; model?: unknown }) => { + generated.push(input) + return { + text: '{"raw_memory":"CSV parser uses strict typed rows.","rollout_summary":"Implemented the typed CSV parser convention.","rollout_slug":"typed-csv-parser"}', + } + }, + }, + catalog: { model: { list: async () => ({ data: [] }) } }, + mcp: { list: async () => ({ data: [] }) }, + } + setV2Context(ctx) + setPluginInput({ client: buildV1ClientShim() } as any) + recordSessionSighting(SESSION_ID, { title: "pipe", directory: "/project", updated: updatedAt }) + + const store = new MemoryStore() + await runPhase1(store, { + ...DEFAULT_PHASE1_OPTIONS, + maxClaimed: 1, + extractModel: "test/extractor", + }, async () => ({ ok: true })) + + expect(store.stage1Outputs()).toMatchObject([ + { + session_id: SESSION_ID, + raw_memory: "CSV parser uses strict typed rows.", + rollout_slug: "typed-csv-parser", + cwd: "/project", + }, + ]) + // Extraction ran tool-less through generate.text (no helper session). + expect(created).toEqual([]) + expect(generated).toHaveLength(1) + expect((generated[0] as any).model).toEqual({ providerID: "test", id: "extractor", variant: "low" }) + expect((generated[0] as any).prompt).toContain("Use the durable CSV parser convention.") + + const phase2 = await runPhase2(store, { + ...DEFAULT_PHASE2_OPTIONS, + consolidationModel: "test/consolidator", + }) + + expect(phase2.status).toBe("succeeded") + expect(created).toEqual(["sub-consolidate"]) + expect(switched).toContainEqual({ agent: "memorize" }) + expect(switched).toContainEqual({ model: { providerID: "test", id: "consolidator", variant: "medium" } }) + // Helper turn was stopped and released after the run. + expect(interrupted).toContain("sub-consolidate") + + const prompt = buildMemorySystemPrompt(true) + expect(prompt).toContain("CSV parser uses strict typed rows.") + }) +}) diff --git a/tests/v2-plugin.test.ts b/tests/v2-plugin.test.ts new file mode 100644 index 0000000..fe71897 --- /dev/null +++ b/tests/v2-plugin.test.ts @@ -0,0 +1,309 @@ +import { describe, it, expect, beforeEach, afterEach } from "bun:test" +import fs from "fs" +import os from "os" +import path from "path" +import { setup, waitForV2BackgroundTasks, resetV2ModuleStateForTest } from "../src/v2/plugin.js" +import { setV2Context, clearSessionRegistryForTest } from "../src/v2/shim.js" +import { setPluginInput } from "../src/llm.js" +import { resetPluginOptions } from "../src/options.js" +import { resetAgentHealth } from "../src/agent-health.js" +import { MemoryStore } from "../src/store.js" +import { parseMemoryStatus } from "../src/v2/status-rpc.js" + +const TEST_ROOT = path.join(os.tmpdir(), `ocm-v2plugin-${process.pid}`) + +function fakeCtx(options: Record = {}) { + const added: any[] = [] + const hooks: Record unknown)[]> = {} + const agentUpdates: string[] = [] + const rpcHandlers: Record Promise> = {} + const ctx: any = { + location: { directory: TEST_ROOT }, + options, + rpc: { + register: async (_definition: unknown, handlers: typeof rpcHandlers) => { + Object.assign(rpcHandlers, handlers) + return { events: { emit: async () => {} } } + }, + }, + agent: { + get: async () => { + throw new Error("Agent not found") + }, + transform: async (cb: (e: any) => void) => { + cb({ update: (id: string, fn: (a: any) => void) => { + agentUpdates.push(id) + fn({ id }) + } }) + }, + }, + tool: { + transform: async (cb: (e: any) => void) => { + cb({ add: (t: any) => added.push(t) }) + }, + hook: async (name: string, cb: (e: any) => unknown) => { + ;(hooks[name] ??= []).push(cb) + }, + }, + session: { + hook: async (name: string, cb: (e: any) => unknown) => { + ;(hooks[name] ??= []).push(cb) + }, + create: async () => ({ data: { id: "ses_helper" } }), + get: async () => ({ id: "ses_helper", parentID: null }), + context: async () => [], + prompt: async () => ({ id: "msg_1" }), + wait: async () => {}, + interrupt: async () => ({ interrupted: true }), + switchAgent: async () => {}, + switchModel: async () => {}, + }, + generate: { text: async () => ({ text: "{}" }) }, + catalog: { model: { list: async () => ({ data: [] }) } }, + mcp: { list: async () => ({ data: [] }) }, + event: { + subscribe: async function* () {}, + }, + } + return { ctx, added, hooks, agentUpdates, rpcHandlers } +} + +beforeEach(() => { + fs.mkdirSync(TEST_ROOT, { recursive: true }) + process.env.OPENCODE_CODEX_MEMORY_TEST_ROOT = TEST_ROOT + // Module-singleton DB handle: drop any handle from another test file. + require("../src/db.js").closeDb() + fs.mkdirSync(path.join(TEST_ROOT, "memories"), { recursive: true }) + resetPluginOptions() + resetV2ModuleStateForTest() +}) + +afterEach(() => { + delete process.env.OPENCODE_CODEX_MEMORY_TEST_ROOT + try { + fs.rmSync(TEST_ROOT, { recursive: true, force: true }) + } catch { + } + resetPluginOptions() + resetAgentHealth() + resetV2ModuleStateForTest() + clearSessionRegistryForTest() + setV2Context(null) + setPluginInput({ client: undefined } as any) +}) + +describe("v2 setup", () => { + it("serves read-only status with effective options without starting memory jobs", async () => { + const f = fakeCtx({ + generate_memories: false, + extract_model: "foundry-local/gpt-5.6-luna", + consolidation_model: "foundry-local/gpt-5.6-luna", + codex_interop: { import: true }, + }) + const cleanup = await setup(f.ctx) + const snapshot = parseMemoryStatus(await f.rpcHandlers.status()) + expect(snapshot).toMatchObject({ + activity: "read_only", + extractModel: "foundry-local/gpt-5.6-luna", + consolidationModel: "foundry-local/gpt-5.6-luna", + codexImport: true, + lastSuccessAt: null, + warnings: [], + }) + expect(new MemoryStore().phase2JobSnapshot()).toBeNull() + expect(new MemoryStore().stage1JobSnapshot().by_status).toEqual({}) + await cleanup?.() + }) + + it("reports durable consolidation state and never labels a failure timestamp as success", async () => { + const f = fakeCtx() + const cleanup = await setup(f.ctx) + const store = new MemoryStore() + const first = store.claimGlobalPhase2Job() + if (first.type !== "claimed") throw new Error("expected claim") + expect(parseMemoryStatus(await f.rpcHandlers.status()).activity).toBe("consolidating") + store.markPhase2Succeeded(first.ownershipToken, []) + const success = parseMemoryStatus(await f.rpcHandlers.status()) + expect(success.activity).toBe("idle") + expect(success.lastSuccessAt).toBeGreaterThan(0) + require("../src/db.js").openDb().prepare("UPDATE memory_jobs SET finished_at=1 WHERE kind='memory_consolidate_global'").run() + const next = store.claimGlobalPhase2Job() + if (next.type !== "claimed") throw new Error("expected retry claim") + store.markPhase2Failed(next.ownershipToken, "test failure") + const failed = parseMemoryStatus(await f.rpcHandlers.status()) + expect(failed.activity).toBe("retrying") + expect(failed.retryAt).toBeGreaterThan(Date.now()) + expect(failed.lastSuccessAt).toBeNull() + expect(failed.warnings.length).toBeGreaterThan(0) + await cleanup?.() + }) + + it("reports extraction claims and distinguishes disabled memory from read-only", async () => { + const f = fakeCtx({ generate_memories: false, use_memories: false }) + const cleanup = await setup(f.ctx) + expect(parseMemoryStatus(await f.rpcHandlers.status()).activity).toBe("disabled") + // A job already claimed by another worker remains visible even if this + // location disables future generation. + const store = new MemoryStore() + store.claimStage1Jobs([{ id: "ses_extracting", updated_at: Date.now() }]) + expect(parseMemoryStatus(await f.rpcHandlers.status()).activity).toBe("extracting") + await cleanup?.() + }) + + it("registers tools, hooks and the memorize agent; applies options", async () => { const f = fakeCtx({ generate_memories: false }) + const cleanup = await setup(f.ctx) + expect(f.added.map((t) => t.name).sort()).toEqual( + ["memory_add_note", "memory_inspect", "memory_list", "memory_mode", "memory_read", "memory_reset", "memory_search"].sort(), + ) + expect(Object.keys(f.hooks).sort()).toEqual(["context", "execute.before", "prompt"]) + expect(f.agentUpdates).toEqual([]) + await (cleanup as () => unknown)?.() + await waitForV2BackgroundTasks() + }) + + it("prompt hook stamps the session mode without running the pipeline when generation is off", async () => { + const f = fakeCtx({ generate_memories: false }) + await setup(f.ctx) + await f.hooks.prompt[0]({ sessionID: "ses_new1", prompt: { text: "hi" } }) + await waitForV2BackgroundTasks() + expect(new MemoryStore().getMemoryMode("ses_new1")).toBe("disabled") + }) + + it("context hook injects the summary as a text system part", async () => { + fs.writeFileSync(path.join(TEST_ROOT, "memories", "memory_summary.md"), "- v2 memory [[ses_x]]\n") + const f = fakeCtx() + await setup(f.ctx) + const ev: any = { sessionID: "ses_x", system: [], messages: [] } + await f.hooks.context[0](ev) + expect(ev.system).toHaveLength(1) + expect(ev.system[0].type).toBe("text") + expect(ev.system[0].text).toContain("v2 memory") + }) + + it("context hook strips citations from assistant parts", async () => { + const f = fakeCtx() + await setup(f.ctx) + const ev: any = { + sessionID: "ses_x", + system: [], + messages: [ + { + id: "m1", + type: "assistant", + content: [{ type: "text", text: "x ses_q" }], + }, + ], + } + await f.hooks.context[0](ev) + expect(ev.messages[0].content[0].text).toBe("x") + expect(ev.messages[0].content[0].text).not.toContain("memory-citation") + }) + + it("tool hook marks websearch sessions polluted when the guard is on", async () => { + const f = fakeCtx() + await setup(f.ctx) + const { applyPluginOptions } = require("../src/index.js") + applyPluginOptions({ disable_on_external_context: true }) + await f.hooks["execute.before"][0]({ tool: "websearch", sessionID: "ses_pol" }) + expect(new MemoryStore().isPolluted("ses_pol")).toBe(true) + }) +}) + +describe("v2 tui status panel", () => { + function fakeTuiCtx(status: unknown) { + const claims: any[] = [] + const layers: any[] = [] + const ctx: any = { + location: { directory: TEST_ROOT }, + data: { location: { default: () => ({ directory: TEST_ROOT }) } }, + client: { + rpc: () => ({ + status: async () => structuredClone(status), + events: { on: () => () => {} }, + }), + }, + keymap: { layer: (fn: () => unknown) => { layers.push(fn()); return () => {} } }, + ui: { + slot: (claim: unknown) => { claims.push(claim); return () => {} }, + dialog: { alert: async () => {} }, + }, + theme: { + text: { + default: "#fff", + subdued: "#888", + status: { running: "#0f0" }, + feedback: { error: { default: "#f00" }, warning: { default: "#ff0" } }, + }, + }, + } + return { ctx, claims, layers } + } + + it("registers sidebar + app slots in setup without touching Solid-scoped APIs", async () => { + const tui = await import("../src/v2/tui.js") + const f = fakeTuiCtx(null) + // Must not throw: keymap.layer outside a component scope fails on the host. + const cleanup = await (tui.default.setup as any)(f.ctx) + expect(claimsTargets(f)).toEqual(["app", "sidebar.content"]) + expect(f.layers).toEqual([]) + await (cleanup as any)?.() + }) + + function claimsTargets(f: { claims: any[] }): string[] { + return f.claims.map((c) => c.append).sort() + } + + it("mounts the app layer from a component scope and serves the status command", async () => { + const { createRoot } = await import("solid-js") + const tui = await import("../src/v2/tui.js") + const seen: any[] = [] + const f = fakeTuiCtx(null) + f.ctx.ui.dialog.alert = async (opts: unknown) => { seen.push(opts) } + const cleanup = await (tui.default.setup as any)(f.ctx) + const app = f.claims.find((c) => c.append === "app") + createRoot((dispose: () => void) => { + app.render({}) + dispose() + }) + expect(f.layers).toHaveLength(1) + const run = f.layers[0].commands[0].run + expect(f.layers[0].commands[0].slash).toEqual({ name: "memory-status" }) + await run() + expect((seen[0] as any).title).toBe("Memory status") + expect((seen[0] as any).message).toContain("Memory status is unavailable") + await (cleanup as any)?.() + }) + + it("renders the sidebar panel without orphan-text errors", async () => { + const { testRender } = await import("@opentui/solid") + const tui = await import("../src/v2/tui.js") + const f = fakeTuiCtx({ + activity: "idle", + useMemories: true, + generateMemories: true, + extractModel: "m", + consolidationModel: "m", + codexImport: false, + lastSuccessAt: null, + retryAt: null, + warnings: [], + }) + const cleanup = await (tui.default.setup as any)(f.ctx) + const panel = f.claims.find((c) => c.append === "sidebar.content") + // Threw before the placeholder fix: a bare text node under . + const rendered: any = await testRender(() => panel.render({ sessionID: "ses_x" }) as any) + await rendered.flush() + const frame = rendered.captureCharFrame() as string + expect(frame).toContain("Memory") + expect(frame).toContain("/memory-status") + // JSX trims leading whitespace of inline literals, so the hint line must + // be a string expression to keep its indent aligned with the labels. + expect(frame.split("\n").some((line) => line.startsWith(" /memory-status"))).toBe(true) + try { + ;(rendered.renderer as any)?.dispose?.() + ;(rendered.renderer as any)?.stop?.() + } catch { + } + await (cleanup as any)?.() + }) +}) diff --git a/tests/v2-shim.test.ts b/tests/v2-shim.test.ts new file mode 100644 index 0000000..39d795c --- /dev/null +++ b/tests/v2-shim.test.ts @@ -0,0 +1,213 @@ +import { describe, it, expect, beforeEach } from "bun:test" +import { + setV2Context, + buildV1ClientShim, + recordSessionSighting, + clearSessionRegistryForTest, + adaptV2Messages, + adaptProviderCatalog, + adaptMcpStatus, +} from "../src/v2/shim.js" +import { catalogVariantKeys } from "../src/reasoning-variant.js" + +const ASSISTANT_TOOL_MSG = { + id: "msg_tool1", + time: { created: 1788872021828, streamed: 1788872023623, completed: 1788872023624 }, + type: "assistant", + agent: "build", + model: { id: "gpt-6-astra", providerID: "github-copilot" }, + content: [ + { + type: "tool", + id: "call_1", + name: "execute", + executed: false, + state: { + status: "completed", + input: { code: 'return await tools.memory_read({path: "MEMORY.md"});' }, + content: [{ type: "text", text: "# memories" }], + metadata: { toolCalls: [{ tool: "memory_read", status: "completed", input: { path: "MEMORY.md" } }] }, + }, + }, + { type: "text", text: "done ses_abc" }, + { type: "reasoning", text: "should be dropped" }, + ], + finish: "tool-calls", +} + +function fakeCtx() { + const calls: { name: string; args: unknown }[] = [] + const ctx: any = { + location: { directory: "/tmp/v2test" }, + options: {}, + session: { + create: async (a: unknown) => { + calls.push({ name: "create", args: a }) + return { data: { id: "ses_created1" } } + }, + prompt: async (a: unknown) => { + calls.push({ name: "prompt", args: a }) + return { id: "msg_1" } + }, + wait: async (a: unknown) => { + calls.push({ name: "wait", args: a }) + }, + context: async (a: unknown) => { + calls.push({ name: "context", args: a }) + return [{ id: "m1", time: { created: 1 }, text: "hi", type: "user" }] + }, + get: async (a: any) => { + calls.push({ name: "get", args: a }) + if (a.sessionID === "ses_gone") throw { _tag: "SessionNotFoundError" } + return { id: a.sessionID, parentID: null } + }, + switchAgent: async (a: unknown) => { + calls.push({ name: "switchAgent", args: a }) + }, + switchModel: async (a: unknown) => { + calls.push({ name: "switchModel", args: a }) + }, + interrupt: async (a: unknown) => { + calls.push({ name: "interrupt", args: a }) + return { interrupted: true } + }, + }, + generate: { + text: async (a: unknown) => { + calls.push({ name: "generate", args: a }) + return { text: '{"raw_memory":"m","rollout_summary":"s","rollout_slug":"t"}' } + }, + }, + catalog: { + model: { + list: async () => ({ + data: [{ providerID: "acme", modelID: "m1", variants: [{ id: "low" }, { id: "high" }] }], + }), + }, + }, + mcp: { + list: async () => ({ data: [{ name: "srv", status: { status: "connected" } }] }), + }, + } + return { ctx, calls } +} + +beforeEach(() => { + clearSessionRegistryForTest() + setV2Context(null) +}) + +describe("adaptV2Messages", () => { + it("maps user/assistant rows to V1 capture shape", () => { + const rows = adaptV2Messages([ + { id: "u1", time: { created: 1 }, text: "hello", type: "user" }, + ASSISTANT_TOOL_MSG, + { id: "s1", time: { created: 2 }, text: "sys", type: "system" }, + ]) + expect(rows).toHaveLength(3) + expect(rows[0]).toEqual({ info: { role: "user" }, parts: [{ type: "text", text: "hello" }] }) + expect(rows[2].info?.role).toBe("system") + const parts = rows[1].parts as any[] + // execute wrapper expands to per-tool rows; text kept; reasoning dropped. + expect(parts[0]).toEqual({ + type: "tool", + tool: "memory_read", + state: { input: { path: "MEMORY.md" }, output: "# memories" }, + }) + expect(parts[1]).toEqual({ + type: "text", + text: "done ses_abc", + }) + expect(parts.some((p) => p.type === "reasoning" && (p as any).text !== undefined)).toBe(false) + }) + + it("returns [] for non-arrays", () => { + expect(adaptV2Messages(null)).toEqual([]) + }) +}) + +describe("catalog/mcp adapters", () => { + it("adapts provider catalog for variant mapping", () => { + const v1 = adaptProviderCatalog({ data: [{ providerID: "acme", modelID: "m1", variants: [{ id: "low" }, { id: "high" }] }] }) + expect(catalogVariantKeys(v1, "acme", "m1")?.sort()).toEqual(["high", "low"]) + expect(catalogVariantKeys(v1, "nope", "m1")).toBeUndefined() + }) + + it("adapts mcp list to status map", () => { + expect(adaptMcpStatus({ data: [{ name: "srv", status: { status: "connected" } }] })).toEqual({ + srv: { status: "connected" }, + }) + }) +}) + +describe("V1 client shim", () => { + it("serves discovery from the registry in listGlobal shape", async () => { + const { ctx } = fakeCtx() + setV2Context(ctx as any) + recordSessionSighting("ses_b", { title: "b", directory: "/p" }) + recordSessionSighting("ses_a", { title: "codex-memory-x", directory: "/p" }) + const client = buildV1ClientShim() as any + const res = await client._client.get({ url: "/experimental/session", query: { roots: true, limit: 10, directory: "" } }) + expect(Array.isArray(res.data)).toBe(true) + expect(res.data).toHaveLength(2) + // capture.ts filters titles/parents itself; rows carry what it needs. + expect(res.data[0].time.updated).toBeGreaterThanOrEqual(res.data[1].time.updated) + await new Promise((r) => setTimeout(r, 10)) + }) + + it("routes structured extraction through generate.text", async () => { + const { ctx, calls } = fakeCtx() + setV2Context(ctx as any) + const client = buildV1ClientShim() as any + const res = await client.session.prompt({ + path: { id: "ses_x" }, + body: { + agent: "memorize-extract", + system: "SYS", + model: { providerID: "acme", modelID: "m1" }, + variant: "low", + format: { type: "json_schema" }, + parts: [{ type: "text", text: "TRANSCRIPT" }], + }, + }) + expect(calls.map((c) => c.name)).toEqual(["generate"]) + const gen = calls[0].args as any + expect(gen.prompt).toContain("SYS") + expect(gen.prompt).toContain("TRANSCRIPT") + expect(gen.model).toEqual({ providerID: "acme", id: "m1", variant: "low" }) + expect(JSON.stringify(res.data)).toContain("raw_memory") + }) + + it("routes agentic prompts through switch + prompt + wait", async () => { + const { ctx, calls } = fakeCtx() + setV2Context(ctx as any) + const client = buildV1ClientShim() as any + await client.session.prompt({ + path: { id: "ses_y" }, + body: { agent: "memorize", model: { providerID: "acme", modelID: "m1" }, parts: [{ type: "text", text: "DO" }] }, + }) + expect(calls.map((c) => c.name)).toEqual(["switchAgent", "switchModel", "prompt", "wait"]) + expect((calls[2].args as any).text).toBe("DO") + }) + + it("maps NotFound gets to 404 and released ids stay 404", async () => { + const { ctx } = fakeCtx() + setV2Context(ctx as any) + const client = buildV1ClientShim() as any + const gone = await client.session.get({ path: { id: "ses_gone" } }) + expect(gone.response?.status).toBe(404) + const live = await client.session.get({ path: { id: "ses_live" } }) + expect(live.data?.id).toBe("ses_live") + await client.session.delete({ path: { id: "ses_live" } }) + const after = await client.session.get({ path: { id: "ses_live" } }) + expect(after.response?.status).toBe(404) + }) + + it("adapts context() into messages rows", async () => { + const { ctx } = fakeCtx() + setV2Context(ctx as any) + const client = buildV1ClientShim() as any + const res = await client.session.messages({ path: { id: "ses_live" } }) + expect(res.data).toEqual([{ info: { role: "user" }, parts: [{ type: "text", text: "hi" }] }]) + }) +}) diff --git a/tests/v2-tools.test.ts b/tests/v2-tools.test.ts new file mode 100644 index 0000000..6febb7d --- /dev/null +++ b/tests/v2-tools.test.ts @@ -0,0 +1,90 @@ +import { describe, it, expect, beforeEach, afterEach } from "bun:test" +import fs from "fs" +import os from "os" +import path from "path" +import { buildV2Tools } from "../src/v2/tools.js" +import { resetPluginOptions } from "../src/options.js" +import { applyPluginOptions } from "../src/index.js" +import { MemoryStore } from "../src/store.js" + +const TEST_ROOT = path.join(os.tmpdir(), `ocm-v2tools-${process.pid}`) + +beforeEach(() => { + fs.mkdirSync(TEST_ROOT, { recursive: true }) + process.env.OPENCODE_CODEX_MEMORY_TEST_ROOT = TEST_ROOT + // Module-singleton DB handle: drop any handle from another test file. + require("../src/db.js").closeDb() + const root = path.join(TEST_ROOT, "memories") + fs.mkdirSync(root, { recursive: true }) + resetPluginOptions() +}) + +afterEach(() => { + delete process.env.OPENCODE_CODEX_MEMORY_TEST_ROOT + try { + fs.rmSync(TEST_ROOT, { recursive: true, force: true }) + } catch { + } + resetPluginOptions() +}) + +const TCTX = { sessionID: "ses_test", messageID: "msg_test", agent: "build" } + +describe("buildV2Tools gating", () => { + it("registers all 7 tools by default", () => { + expect(buildV2Tools().map((t) => t.name).sort()).toEqual( + ["memory_add_note", "memory_inspect", "memory_list", "memory_mode", "memory_read", "memory_reset", "memory_search"].sort(), + ) + }) + + it("registers only control tools when dedicated_tools is off", () => { + applyPluginOptions({ dedicated_tools: false }) + expect(buildV2Tools().map((t) => t.name).sort()).toEqual(["memory_inspect", "memory_mode", "memory_reset"]) + }) + + it("registers only control tools when use_memories is off", () => { + applyPluginOptions({ use_memories: false }) + expect(buildV2Tools().map((t) => t.name).sort()).toEqual(["memory_inspect", "memory_mode", "memory_reset"]) + }) +}) + +describe("adapted tool execution", () => { + it("memory_read returns content through the V2 shape", async () => { + fs.writeFileSync(path.join(TEST_ROOT, "memories", "READ.md"), "# hi\n") + const def = buildV2Tools().find((t) => t.name === "memory_read")! + const res = await def.execute({ path: "READ.md" }, TCTX) + expect(res.content).toContain("# hi") + }) + + it("memory_list applies schema defaults", async () => { + fs.writeFileSync(path.join(TEST_ROOT, "memories", "a.md"), "x") + const def = buildV2Tools().find((t) => t.name === "memory_list")! + const parsed = (def.input as any).parse({}) + expect(parsed.path).toBe("") + const res = await def.execute(parsed, TCTX) + expect(res.content).toContain("a.md") + }) + + it("memory_add_note + memory_mode round-trip with the calling session", async () => { + const add = buildV2Tools().find((t) => t.name === "memory_add_note")! + const saved = await add.execute({ note: "v2 note", title: "t" }, TCTX) + expect(saved.content).toContain("Note saved to") + const mode = buildV2Tools().find((t) => t.name === "memory_mode")! + const set = await mode.execute({ mode: "disabled" }, TCTX) + expect(set.content).toContain("ses_test") + expect(new MemoryStore().getMemoryMode("ses_test")).toBe("disabled") + }) + + it("memory_search finds workspace content", async () => { + fs.writeFileSync(path.join(TEST_ROOT, "memories", "MEMORY.md"), "quokka tracking\n") + const def = buildV2Tools().find((t) => t.name === "memory_search")! + const res = await def.execute({ queries: ["quokka"] }, TCTX) + expect(res.content).toContain("quokka") + }) + + it("memory_inspect renders state", async () => { + const def = buildV2Tools().find((t) => t.name === "memory_inspect")! + const res = await def.execute({}, TCTX) + expect(res.content).toContain("stage1_outputs") + }) +}) diff --git a/tsconfig.json b/tsconfig.json index b6fe71b..bec344d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,8 @@ "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "declaration": true, + "jsx": "preserve", + "jsxImportSource": "@opentui/solid", "outDir": "dist", "rootDir": ".", "baseUrl": ".", @@ -18,6 +20,6 @@ "@/*": ["./src/*"] } }, - "include": ["src/**/*.ts", "tools/**/*.ts"], + "include": ["src/**/*.ts", "src/**/*.tsx", "tools/**/*.ts"], "exclude": ["node_modules", "dist", "tests"] -} \ No newline at end of file +}