From fbc2371b95f9333e59ee3a46b8b62725ded962a9 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 19 Apr 2026 14:45:01 +0800 Subject: [PATCH] feat(server): replace Pi ACP with direct SDK provider (#202) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(server): replace Pi ACP integration with direct SDK provider Replace the ACP-based Pi provider (which spawned a `pi-acp` subprocess and talked JSON-RPC over stdio) with a direct in-process integration using `@mariozechner/pi-coding-agent` as a library. The new `PiDirectAgentClient` and `PiDirectAgentSession` use the Pi SDK directly — creating sessions via `createAgentSession()`, managing models via `ModelRegistry`, and mapping Pi's `AgentSessionEvent` stream to Paseo's `AgentStreamEvent` types including: - Thread/turn lifecycle events - Assistant text and thinking/reasoning deltas - Tool execution (bash, read, write, edit, find, grep, ls) with arg caching across start/update/end events - Compaction events - Session persistence and resume via `SessionManager` Thinking levels flow through the existing `thinkingOptionId` / `setThinkingOption()` infrastructure, not through features. Includes 9 real e2e tests against a live Pi agent covering tool calls (bash/read/write/edit), reasoning chunks, session persistence/resume, model listing, and thinking option management. Co-Authored-By: Claude Opus 4.6 * fix: update lockfile signatures and Nix hash * refactor(server): improve Pi direct provider code quality Address coding standards violations in pi-direct-agent.ts: - Replace all `as Record` / `as any` / `as unknown as` casts with properly typed boundaries using Pi SDK's exported tool input types (BashToolInput, ReadToolInput, EditToolInput, etc.) - Introduce named interfaces at all boundaries: PiPromptPayload, ToolCallOutputSummary, PiModelReference, PiPersistenceMetadata - Parse tool args once at boundary into typed discriminated union, then trust types internally — no more typeof probing in mappers - Break all dense ternary chains into named steps / helper functions - Import SDK types directly (RegisteredCommand, ResourceLoader, Skill) instead of casting through anonymous inline shapes - Isolate the system prompt SDK escape hatch into a minimal boundary helper with a named interface Behavior is preserved — all 9 real e2e tests still pass. Co-Authored-By: Claude Opus 4.6 * fix: regenerate package-lock.json with resolved/integrity fields The previous lockfile regeneration ran under an offline/cached npm context and stripped resolved URLs and integrity hashes from existing entries, which would break npm ci and Nix builds. * fix: update Nix npmDepsHash for regenerated lockfile * chore(server): bump @mariozechner/pi-coding-agent to ^0.67.68 * fix: update lockfile signatures and Nix hash * fix(app): surface agent setter RPC errors as toasts setAgentMode/Model/ThinkingOption/Feature errors from the daemon were only logged to console, so failures like missing API keys silently vanished. Add toast.error fallbacks at all call sites and hoist ToastProvider above SessionProvider so session context can use it. --------- Co-authored-by: Claude Opus 4.6 Co-authored-by: github-actions[bot] --- nix/package.nix | 2 +- package-lock.json | 2743 ++++++++++++++++- packages/app/src/app/_layout.tsx | 16 +- .../app/src/components/agent-status-bar.tsx | 7 + packages/app/src/contexts/session-context.tsx | 12 +- packages/server/package.json | 2 +- .../server/agent/provider-registry.test.ts | 4 +- .../src/server/agent/provider-registry.ts | 4 +- .../server/agent/providers/acp-agent.test.ts | 288 +- .../server/agent/providers/claude-agent.ts | 13 +- .../server/agent/providers/pi-acp-agent.ts | 406 --- .../server/agent/providers/pi-direct-agent.ts | 1442 +++++++++ .../src/server/daemon-e2e/agent-configs.ts | 4 +- .../src/server/daemon-e2e/pi.real.e2e.test.ts | 472 ++- 14 files changed, 4605 insertions(+), 810 deletions(-) delete mode 100644 packages/server/src/server/agent/providers/pi-acp-agent.ts create mode 100644 packages/server/src/server/agent/providers/pi-direct-agent.ts diff --git a/nix/package.nix b/nix/package.nix index 61f6c9f19..08320f935 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -42,7 +42,7 @@ buildNpmPackage rec { # To update: run `nix build` with lib.fakeHash, copy the `got:` hash. # CI auto-updates this when package-lock.json changes (see .github/workflows/). - npmDepsHash = "sha256-wiHIGfS9gEPq0CTjx8O+wbQezEB9HYWEia4vnJ5/VAQ="; + npmDepsHash = "sha256-n1Q7uZumewPUZZFacSkSXeLotTApjxq+BpDEQ8V2MQs="; # Prevent onnxruntime-node's install script from running during automatic # npm rebuild (it tries to download from api.nuget.org, which fails in the sandbox). diff --git a/package-lock.json b/package-lock.json index 188b5d724..c230c4747 100644 --- a/package-lock.json +++ b/package-lock.json @@ -145,6 +145,701 @@ "zod": "^4.0.0" } }, + "node_modules/@aws-crypto/crc32": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", + "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "license": "Apache-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" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1032.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1032.0.tgz", + "integrity": "sha512-fSRz/48As9c3DeS+9ZWd7kk9171pJntCCuehHBDeprD9CPF+C+ATaVNJ5SOLE5RIBR2IHOVTwjAgJt/nkS/6Yg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/credential-provider-node": "^3.972.32", + "@aws-sdk/eventstream-handler-node": "^3.972.14", + "@aws-sdk/middleware-eventstream": "^3.972.10", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-user-agent": "^3.972.31", + "@aws-sdk/middleware-websocket": "^3.972.16", + "@aws-sdk/region-config-resolver": "^3.972.12", + "@aws-sdk/token-providers": "3.1032.0", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.7", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.17", + "@smithy/config-resolver": "^4.4.16", + "@smithy/core": "^3.23.15", + "@smithy/eventstream-serde-browser": "^4.2.14", + "@smithy/eventstream-serde-config-resolver": "^4.3.14", + "@smithy/eventstream-serde-node": "^4.2.14", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.30", + "@smithy/middleware-retry": "^4.5.3", + "@smithy/middleware-serde": "^4.2.18", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.5.3", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.11", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-body-length-node": "^4.2.3", + "@smithy/util-defaults-mode-browser": "^4.3.47", + "@smithy/util-defaults-mode-node": "^4.2.52", + "@smithy/util-endpoints": "^3.4.1", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.2", + "@smithy/util-stream": "^4.5.23", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.974.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.974.1.tgz", + "integrity": "sha512-gy/gffKz0zaHDaqRiLCdIvgHmaAL/HXuAtMcBP7euYSFx4BsbsdlfmUBJag+Gqe62z6/XuloKyQyaiH+kS3Vrg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/xml-builder": "^3.972.18", + "@smithy/core": "^3.23.15", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/smithy-client": "^4.12.11", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.27", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.27.tgz", + "integrity": "sha512-xfUt2CUZDC+Tf16A6roD1b4pk/nrXdkoLY3TEhv198AXDtBo5xUJP1zd0e8SmuKLN4PpIBX96OizZbmMlcI6oQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.29", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.29.tgz", + "integrity": "sha512-hjNeYb6oLyHgMihra83ie0J/T2y9om3cy1qC90h9DRgvYXEoN4BCFf8bHguZjKhXunnv7YkmZRuYL5Mkk77eCA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/node-http-handler": "^4.5.3", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.11", + "@smithy/types": "^4.14.1", + "@smithy/util-stream": "^4.5.23", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.972.31", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.972.31.tgz", + "integrity": "sha512-PuQ7e8WYzAPpzvFcajxf8c0LqSzakVHVlKw8M0oubk8Kf347YOCCqT1seQrHs5AdZuIh2RD9LX4O+Xa5ImEBfQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/credential-provider-env": "^3.972.27", + "@aws-sdk/credential-provider-http": "^3.972.29", + "@aws-sdk/credential-provider-login": "^3.972.31", + "@aws-sdk/credential-provider-process": "^3.972.27", + "@aws-sdk/credential-provider-sso": "^3.972.31", + "@aws-sdk/credential-provider-web-identity": "^3.972.31", + "@aws-sdk/nested-clients": "^3.996.21", + "@aws-sdk/types": "^3.973.8", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.31", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.31.tgz", + "integrity": "sha512-bBmWDmtSpmLOZR6a0kmowBcVL1hiL8Vlap/RXeMpFd7JbWl87YcwqL6T9LH/0oBVEZXu1dUZAtojgSuZgMO5xw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/nested-clients": "^3.996.21", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.32", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.32.tgz", + "integrity": "sha512-9aj0x9hGYUondBZSD0XkksAdHhOKttFw4BWpLCeggeg40qSJxGrAP++g0GCm0VqWc1WtC/NRFiAVzPCy56vmog==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.27", + "@aws-sdk/credential-provider-http": "^3.972.29", + "@aws-sdk/credential-provider-ini": "^3.972.31", + "@aws-sdk/credential-provider-process": "^3.972.27", + "@aws-sdk/credential-provider-sso": "^3.972.31", + "@aws-sdk/credential-provider-web-identity": "^3.972.31", + "@aws-sdk/types": "^3.973.8", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.27", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.27.tgz", + "integrity": "sha512-1CZvfb1WzudWWIFAVQkd1OI/T1RxPcSvNWzNsb2BMBVsBJzBtB8dV5f2nymHVU4UqwxipdVt/DAbgdDRf33JDg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.972.31", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.972.31.tgz", + "integrity": "sha512-x8Mx18S48XMl9bEEpYwmXDTvjWGPIfDadReN37Lc099/DUrlL4Zs9T9rwwggo6DkKS1aev6v+MTUx7JTa87TZQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/nested-clients": "^3.996.21", + "@aws-sdk/token-providers": "3.1032.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.31", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.31.tgz", + "integrity": "sha512-zfuNMIkGfjYsHis9qytYf74Bcmq6Ji9Xwf4w53baRCI/b2otTwZv3SW1uRiJ5Di7999QzRGhHZ96+eUeo3gSOA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/nested-clients": "^3.996.21", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.14", + "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.14.tgz", + "integrity": "sha512-m4X56gxG76/CKfxNVbOFuYwnAZcHgS6HOH8lgp15HoGHIAVTcZfZrXvcYzJFOMLEJgVn+JHBu6EiNV+xSNXXFg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/eventstream-codec": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.10.tgz", + "integrity": "sha512-QUqLs7Af1II9X4fCRAu+EGHG3KHyOp4RkuLhRKoA3NuFlh6TL8i+zXBl8w2LUxqm44B/Kom45hgSlwA1SpTsXQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.972.10.tgz", + "integrity": "sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.972.10.tgz", + "integrity": "sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.972.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.972.11.tgz", + "integrity": "sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.972.31", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.972.31.tgz", + "integrity": "sha512-L+hXN2HDomlIsWSHW5DVD7ppccCeRnlHXZ5uHG34ePTjF5bm0I1fmrJLbUGiW97xRXWryit5cjdP4Sx2FwiGog==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.7", + "@smithy/core": "^3.23.15", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-retry": "^4.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.16", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.16.tgz", + "integrity": "sha512-86+S9oCyRVGzoMRpQhxkArp7kD2K75GPmaNevd9B6EyNhWoNvnCZZ3WbgN4j7ZT+jvtvBCGZvI2XHsWZJ+BRIg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-format-url": "^3.972.10", + "@smithy/eventstream-codec": "^4.2.14", + "@smithy/eventstream-serde-browser": "^4.2.14", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/protocol-http": "^5.3.14", + "@smithy/signature-v4": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-hex-encoding": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.996.21", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.996.21.tgz", + "integrity": "sha512-Me3d/ua2lb2G0bQfFmvCeQQp3+nN6GSPqMxDmi/IQlQ8CrlpQ5C0JJHpz2AnOUkEFI0lBNrAL3Vnt29l44ndkA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/middleware-host-header": "^3.972.10", + "@aws-sdk/middleware-logger": "^3.972.10", + "@aws-sdk/middleware-recursion-detection": "^3.972.11", + "@aws-sdk/middleware-user-agent": "^3.972.31", + "@aws-sdk/region-config-resolver": "^3.972.12", + "@aws-sdk/types": "^3.973.8", + "@aws-sdk/util-endpoints": "^3.996.7", + "@aws-sdk/util-user-agent-browser": "^3.972.10", + "@aws-sdk/util-user-agent-node": "^3.973.17", + "@smithy/config-resolver": "^4.4.16", + "@smithy/core": "^3.23.15", + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/hash-node": "^4.2.14", + "@smithy/invalid-dependency": "^4.2.14", + "@smithy/middleware-content-length": "^4.2.14", + "@smithy/middleware-endpoint": "^4.4.30", + "@smithy/middleware-retry": "^4.5.3", + "@smithy/middleware-serde": "^4.2.18", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/node-http-handler": "^4.5.3", + "@smithy/protocol-http": "^5.3.14", + "@smithy/smithy-client": "^4.12.11", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-body-length-node": "^4.2.3", + "@smithy/util-defaults-mode-browser": "^4.3.47", + "@smithy/util-defaults-mode-node": "^4.2.52", + "@smithy/util-endpoints": "^3.4.1", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.972.12", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.972.12.tgz", + "integrity": "sha512-QQI43Mxd53nBij0pm8HXC+t4IOC6gnhhZfzxE0OATQyO6QfPV4e+aTIRRuAJKA6Nig/cR8eLwPryqYTX9ZrjAQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/config-resolver": "^4.4.16", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1032.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1032.0.tgz", + "integrity": "sha512-n+PU8Z+gll7p3wDrH+Wo6fkt8sPrVnq30YYM6Ryga95oJlEneNMEbDHj0iqjMX3V7gaGdJo/hJWyPo4lscP+mA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.1", + "@aws-sdk/nested-clients": "^3.996.21", + "@aws-sdk/types": "^3.973.8", + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.973.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", + "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.996.7", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.996.7.tgz", + "integrity": "sha512-ty4LQxN1QC+YhUP28NfEgZDEGXkyqOQy+BDriBozqHsrYO4JMgiPhfizqOGF7P+euBTZ5Ez6SKlLAMCLo8tzmw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-endpoints": "^3.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-format-url": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-format-url/-/util-format-url-3.972.10.tgz", + "integrity": "sha512-DEKiHNJVtNxdyTeQspzY+15Po/kHm6sF0Cs4HV9Q2+lplB63+DrvdeiSoOSdWEWAoO2RcY1veoXVDz2tWxWCgQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.965.5.tgz", + "integrity": "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.972.10", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.972.10.tgz", + "integrity": "sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.973.8", + "@smithy/types": "^4.14.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.973.17", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.973.17.tgz", + "integrity": "sha512-utF5qjjbuJQuU9VdCkWl7L87sr93cApsrD+uxGfUnlafX8iyEzJrb7EZnufjThURZVTOtelRMXrblWxpefElUg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "^3.972.31", + "@aws-sdk/types": "^3.973.8", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-config-provider": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.18", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.18.tgz", + "integrity": "sha512-BMDNVG1ETXRhl1tnisQiYBef3RShJ1kfZA7x7afivTFMLirfHNTb6U71K569HNXhSXbQZsweHvSDZ6euBw8hPA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "fast-xml-parser": "5.5.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.4.tgz", + "integrity": "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@babel/cli": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.28.6.tgz", @@ -2734,6 +3429,16 @@ "node": ">=14.21.3" } }, + "node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/@clack/core": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.1.0.tgz", @@ -6633,6 +7338,29 @@ "resolved": "packages/website", "link": true }, + "node_modules/@google/genai": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.50.1.tgz", + "integrity": "sha512-YbkX7H9+1Pt8wOt7DDREy8XSoiL6fRDzZQRyaVBarFf8MR3zHGqVdvM4cLbDXqPhxqvegZShgfxb8kw9C7YhAQ==", + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, "node_modules/@gorhom/bottom-sheet": { "version": "5.2.8", "resolved": "https://registry.npmjs.org/@gorhom/bottom-sheet/-/bottom-sheet-5.2.8.tgz", @@ -7938,6 +8666,198 @@ "node": ">=10" } }, + "node_modules/@mariozechner/clipboard": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard/-/clipboard-0.3.2.tgz", + "integrity": "sha512-IHQpksNjo7EAtGuHFU+tbWDp5LarH3HU/8WiB9O70ZEoBPHOg0/6afwSLK0QyNMMmx4Bpi/zl6+DcBXe95nWYA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@mariozechner/clipboard-darwin-arm64": "0.3.2", + "@mariozechner/clipboard-darwin-universal": "0.3.2", + "@mariozechner/clipboard-darwin-x64": "0.3.2", + "@mariozechner/clipboard-linux-arm64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-arm64-musl": "0.3.2", + "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-x64-gnu": "0.3.2", + "@mariozechner/clipboard-linux-x64-musl": "0.3.2", + "@mariozechner/clipboard-win32-arm64-msvc": "0.3.2", + "@mariozechner/clipboard-win32-x64-msvc": "0.3.2" + } + }, + "node_modules/@mariozechner/clipboard-darwin-arm64": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-arm64/-/clipboard-darwin-arm64-0.3.2.tgz", + "integrity": "sha512-uBf6K7Je1ihsgvmWxA8UCGCeI+nbRVRXoarZdLjl6slz94Zs1tNKFZqx7aCI5O1i3e0B6ja82zZ06BWrl0MCVw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-darwin-universal": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-universal/-/clipboard-darwin-universal-0.3.2.tgz", + "integrity": "sha512-mxSheKTW2U9LsBdXy0SdmdCAE5HqNS9QUmpNHLnfJ+SsbFKALjEZc5oRrVMXxGQSirDvYf5bjmRyT0QYYonnlg==", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-darwin-x64": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-x64/-/clipboard-darwin-x64-0.3.2.tgz", + "integrity": "sha512-U1BcVEoidvwIp95+HJswSW+xr28EQiHR7rZjH6pn8Sja5yO4Yoe3yCN0Zm8Lo72BbSOK/fTSq0je7CJpaPCspg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-arm64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-gnu/-/clipboard-linux-arm64-gnu-0.3.2.tgz", + "integrity": "sha512-BsinwG3yWTIjdgNCxsFlip7LkfwPk+ruw/aFCXHUg/fb5XC/Ksp+YMQ7u0LUtiKzIv/7LMXgZInJQH6gxbAaqQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-arm64-musl": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-musl/-/clipboard-linux-arm64-musl-0.3.2.tgz", + "integrity": "sha512-0/Gi5Xq2V6goXBop19ePoHvXsmJD9SzFlO3S+d6+T2b+BlPcpOu3Oa0wTjl+cZrLAAEzA86aPNBI+VVAFDFPKw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-riscv64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-riscv64-gnu/-/clipboard-linux-riscv64-gnu-0.3.2.tgz", + "integrity": "sha512-2AFFiXB24qf0zOZsxI1GJGb9wQGlOJyN6UwoXqmKS3dpQi/l6ix30IzDDA4c4ZcCcx4D+9HLYXhC1w7Sov8pXA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-x64-gnu": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-gnu/-/clipboard-linux-x64-gnu-0.3.2.tgz", + "integrity": "sha512-v6fVnsn7WMGg73Dab8QMwyFce7tzGfgEixKgzLP8f1GJqkJZi5zO4k4FOHzSgUufgLil63gnxvMpjWkgfeQN7A==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-linux-x64-musl": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-musl/-/clipboard-linux-x64-musl-0.3.2.tgz", + "integrity": "sha512-xVUtnoMQ8v2JVyfJLKKXACA6avdnchdbBkTsZs8BgJQo29qwCp5NIHAUO8gbJ40iaEGToW5RlmVk2M9V0HsHEw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-win32-arm64-msvc": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-arm64-msvc/-/clipboard-win32-arm64-msvc-0.3.2.tgz", + "integrity": "sha512-AEgg95TNi8TGgak2wSXZkXKCvAUTjWoU1Pqb0ON7JHrX78p616XUFNTJohtIon3e0w6k0pYPZeCuqRCza/Tqeg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/clipboard-win32-x64-msvc": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-x64-msvc/-/clipboard-win32-x64-msvc-0.3.2.tgz", + "integrity": "sha512-tGRuYpZwDOD7HBrCpyRuhGnHHSCknELvqwKKUG4JSfSB7JIU7LKRh6zx6fMUOQd8uISK35TjFg5UcNih+vJhFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@mariozechner/jiti": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@mariozechner/jiti/-/jiti-2.6.5.tgz", + "integrity": "sha512-faGUlTcXka5l7rv0lP3K3vGW/ejRuOS24RR2aSFWREUQqzjgdsuWNo/IiPqL3kWRGt6Ahl2+qcDAwtdeWeuGUw==", + "license": "MIT", + "dependencies": { + "std-env": "^3.10.0", + "yoctocolors": "^2.1.2" + }, + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, "node_modules/@modelcontextprotocol/sdk": { "version": "1.27.1", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz", @@ -9040,6 +9960,70 @@ "integrity": "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==", "license": "MIT" }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, "node_modules/@radix-ui/primitive": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", @@ -10323,6 +11307,12 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@silvia-odwyer/photon-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@silvia-odwyer/photon-node/-/photon-node-0.3.4.tgz", + "integrity": "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==", + "license": "Apache-2.0" + }, "node_modules/@sinclair/typebox": { "version": "0.27.10", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", @@ -10359,6 +11349,644 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@smithy/config-resolver": { + "version": "4.4.16", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.16.tgz", + "integrity": "sha512-GFlGPNLZKrGfqWpqVb31z7hvYCA9ZscfX1buYnvvMGcRYsQQnhH+4uN6mWWflcD5jB4OXP/LBrdpukEdjl41tg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-config-provider": "^4.2.2", + "@smithy/util-endpoints": "^3.4.1", + "@smithy/util-middleware": "^4.2.14", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "3.23.15", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.23.15.tgz", + "integrity": "sha512-E7GVCgsQttzfujEZb6Qep005wWf4xiL4x06apFEtzQMWYBPggZh/0cnOxPficw5cuK/YjjkehKoIN4YUaSh0UQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-body-length-browser": "^4.2.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-stream": "^4.5.23", + "@smithy/util-utf8": "^4.2.2", + "@smithy/uuid": "^1.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.14.tgz", + "integrity": "sha512-Au28zBN48ZAoXdooGUHemuVBrkE+Ie6RPmGNIAJsFqj33Vhb6xAgRifUydZ2aY+M+KaMAETAlKk5NC5h1G7wpg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.14.tgz", + "integrity": "sha512-erZq0nOIpzfeZdCyzZjdJb4nVSKLUmSkaQUVkRGQTXs30gyUGeKnrYEg+Xe1W5gE3aReS7IgsvANwVPxSzY6Pw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "5.2.0", + "@smithy/types": "^4.14.1", + "@smithy/util-hex-encoding": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.14.tgz", + "integrity": "sha512-8IelTCtTctWRbb+0Dcy+C0aICh1qa0qWXqgjcXDmMuCvPJRnv26hiDZoAau2ILOniki65mCPKqOQs/BaWvO4CQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.14.tgz", + "integrity": "sha512-sqHiHpYRYo3FJlaIxD1J8PhbcmJAm7IuM16mVnwSkCToD7g00IBZzKuiLNMGmftULmEUX6/UAz8/NN5uMP8bVA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.14.tgz", + "integrity": "sha512-Ht/8BuGlKfFTy0H3+8eEu0vdpwGztCnaLLXtpXNdQqiR7Hj4vFScU3T436vRAjATglOIPjJXronY+1WxxNLSiw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-serde-universal": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.14.tgz", + "integrity": "sha512-lWyt4T2XQZUZgK3tQ3Wn0w3XBvZsK/vjTuJl6bXbnGZBHH0ZUSONTYiK9TgjTTzU54xQr3DRFwpjmhp0oLm3gg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-codec": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.3.17", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.17.tgz", + "integrity": "sha512-bXOvQzaSm6MnmLaWA1elgfQcAtN4UP3vXqV97bHuoOrHQOJiLT3ds6o9eo5bqd0TJfRFpzdGnDQdW3FACiAVdw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.14.tgz", + "integrity": "sha512-8ZBDY2DD4wr+GGjTpPtiglEsqr0lUP+KHqgZcWczFf6qeZ/YRjMIOoQWVQlmwu7EtxKTd8YXD8lblmYcpBIA1g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "@smithy/util-buffer-from": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.14.tgz", + "integrity": "sha512-c21qJiTSb25xvvOp+H2TNZzPCngrvl5vIPqPB8zQ/DmJF4QWXO19x1dWfMJZ6wZuuWUPPm0gV8C0cU3+ifcWuw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.2.tgz", + "integrity": "sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.14.tgz", + "integrity": "sha512-xhHq7fX4/3lv5NHxLUk3OeEvl0xZ+Ek3qIbWaCL4f9JwgDZEclPBElljaZCAItdGPQl/kSM4LPMOpy1MYgprpw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "4.4.30", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.30.tgz", + "integrity": "sha512-qS2XqhKeXmdZ4nEQ4cOxIczSP/Y91wPAHYuRwmWDCh975B7/57uxsm5d6sisnUThn2u2FwzMdJNM7AbO1YPsPg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.15", + "@smithy/middleware-serde": "^4.2.18", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "@smithy/url-parser": "^4.2.14", + "@smithy/util-middleware": "^4.2.14", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.5.3.tgz", + "integrity": "sha512-TE8dJNi6JuxzGSxMCVd3i9IEWDndCl3bmluLsBNDWok8olgj65OfkndMhl9SZ7m14c+C5SQn/PcUmrDl57rSFw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.15", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/service-error-classification": "^4.2.14", + "@smithy/smithy-client": "^4.12.11", + "@smithy/types": "^4.14.1", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-retry": "^4.3.2", + "@smithy/uuid": "^1.1.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "4.2.18", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.18.tgz", + "integrity": "sha512-M6CSgnp3v4tYz9ynj2JHbA60woBZcGqEwNjTKjBsNHPV26R1ZX52+0wW8WsZU18q45jD0tw2wL22S17Ze9LpEw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.15", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.14.tgz", + "integrity": "sha512-2dvkUKLuFdKsCRmOE4Mn63co0Djtsm+JMh0bYZQupN1pJwMeE8FmQmRLLzzEMN0dnNi7CDCYYH8F0EVwWiPBeA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "4.3.14", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.14.tgz", + "integrity": "sha512-S+gFjyo/weSVL0P1b9Ts8C/CwIfNCgUPikk3sl6QVsfE/uUuO+QsF+NsE/JkpvWqqyz1wg7HFdiaZuj5CoBMRg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.14", + "@smithy/shared-ini-file-loader": "^4.4.9", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.5.3.tgz", + "integrity": "sha512-lc5jFL++x17sPhIwMWJ3YOnqmSjw/2Po6VLDlUIXvxVWRuJwRXnJ4jOBBLB0cfI5BB5ehIl02Fxr1PDvk/kxDw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^5.3.14", + "@smithy/querystring-builder": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.14.tgz", + "integrity": "sha512-WuM31CgfsnQ/10i7NYr0PyxqknD72Y5uMfUMVSniPjbEPceiTErb4eIqJQ+pdxNEAUEWrewrGjIRjVbVHsxZiQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.14.tgz", + "integrity": "sha512-dN5F8kHx8RNU0r+pCwNmFZyz6ChjMkzShy/zup6MtkRmmix4vZzJdW+di7x//b1LiynIev88FM18ie+wwPcQtQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.14.tgz", + "integrity": "sha512-XYA5Z0IqTeF+5XDdh4BBmSA0HvbgVZIyv4cmOoUheDNR57K1HgBp9ukUMx3Cr3XpDHHpLBnexPE3LAtDsZkj2A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "@smithy/util-uri-escape": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.14.tgz", + "integrity": "sha512-hr+YyqBD23GVvRxGGrcc/oOeNlK3PzT5Fu4dzrDXxzS1LpFiuL2PQQqKPs87M79aW7ziMs+nvB3qdw77SqE7Lw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.14.tgz", + "integrity": "sha512-vVimoUnGxlx4eLLQbZImdOZFOe+Zh+5ACntv8VxZuGP72LdWu5GV3oEmCahSEReBgRJoWjypFkrehSj7BWx1HQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "4.4.9", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.9.tgz", + "integrity": "sha512-495/V2I15SHgedSJoDPD23JuSfKAp726ZI1V0wtjB07Wh7q/0tri/0e0DLefZCHgxZonrGKt/OCTpAtP1wE1kQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.14.tgz", + "integrity": "sha512-1D9Y/nmlVjCeSivCbhZ7hgEpmHyY1h0GvpSZt3l0xcD9JjmjVC1CHOozS6+Gh+/ldMH8JuJ6cujObQqfayAVFA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.2", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-hex-encoding": "^4.2.2", + "@smithy/util-middleware": "^4.2.14", + "@smithy/util-uri-escape": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "4.12.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.12.11.tgz", + "integrity": "sha512-wzz/Wa1CH/Tlhxh0s4DQPEcXSxSVfJ59AZcUh9Gu0c6JTlKuwGf4o/3P2TExv0VbtPFt8odIBG+eQGK2+vTECg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.23.15", + "@smithy/middleware-endpoint": "^4.4.30", + "@smithy/middleware-stack": "^4.2.14", + "@smithy/protocol-http": "^5.3.14", + "@smithy/types": "^4.14.1", + "@smithy/util-stream": "^4.5.23", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.1.tgz", + "integrity": "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.14.tgz", + "integrity": "sha512-p06BiBigJ8bTA3MgnOfCtDUWnAMY0YfedO/GRpmc7p+wg3KW8vbXy1xwSu5ASy0wV7rRYtlfZOIKH4XqfhjSQQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.2.tgz", + "integrity": "sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.2.tgz", + "integrity": "sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.3.tgz", + "integrity": "sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.2.tgz", + "integrity": "sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.2.tgz", + "integrity": "sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "4.3.47", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.47.tgz", + "integrity": "sha512-zlIuXai3/SHjQUQ8y3g/woLvrH573SK2wNjcDaHu5e9VOcC0JwM1MI0Sq0GZJyN3BwSUneIhpjZ18nsiz5AtQw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^4.2.14", + "@smithy/smithy-client": "^4.12.11", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "4.2.52", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.52.tgz", + "integrity": "sha512-cQBz8g68Vnw1W2meXlkb3D/hXJU+Taiyj9P8qLJtjREEV9/Td65xi4A/H1sRQ8EIgX5qbZbvdYPKygKLholZ3w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^4.4.16", + "@smithy/credential-provider-imds": "^4.2.14", + "@smithy/node-config-provider": "^4.3.14", + "@smithy/property-provider": "^4.2.14", + "@smithy/smithy-client": "^4.12.11", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-endpoints": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.4.1.tgz", + "integrity": "sha512-wMxNDZJrgS5mQV9oxCs4TWl5767VMgOfqfZ3JHyCkMtGC2ykW9iPqMvFur695Otcc5yxLG8OKO/80tsQBxrhXg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^4.3.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.2.tgz", + "integrity": "sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "4.2.14", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.14.tgz", + "integrity": "sha512-1Su2vj9RYNDEv/V+2E+jXkkwGsgR7dc4sfHn9Z7ruzQHJIEni9zzw5CauvRXlFJfmgcqYP8fWa0dkh2Q2YaQyw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.3.2.tgz", + "integrity": "sha512-2+KTsJEwTi63NUv4uR9IQ+IFT1yu6Rf6JuoBK2WKaaJ/TRvOiOVGcXAsEqX/TQN2thR9yII21kPUJq1UV/WI2A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^4.2.14", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "4.5.23", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.23.tgz", + "integrity": "sha512-N6on1+ngJ3RznZOnDWNveIwnTSlqxNnXuNAh7ez889ZZaRdXoNRTXKgmYOLe6dB0gCmAVtuRScE1hymQFl4hpg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^5.3.17", + "@smithy/node-http-handler": "^4.5.3", + "@smithy/types": "^4.14.1", + "@smithy/util-base64": "^4.3.2", + "@smithy/util-buffer-from": "^4.2.2", + "@smithy/util-hex-encoding": "^4.2.2", + "@smithy/util-utf8": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.2.tgz", + "integrity": "sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.2.tgz", + "integrity": "sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^4.2.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/uuid": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.2.tgz", + "integrity": "sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@speed-highlight/core": { "version": "1.2.14", "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.14.tgz", @@ -11167,6 +12795,29 @@ } } }, + "node_modules/@tokenizer/inflate": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "token-types": "^6.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", + "license": "MIT" + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -11177,6 +12828,12 @@ "node": ">= 10" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, "node_modules/@tsconfig/node10": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", @@ -11649,6 +13306,12 @@ "@types/node": "*" } }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "license": "MIT" + }, "node_modules/@types/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", @@ -11752,7 +13415,6 @@ "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -13941,6 +15603,15 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/basic-ftp": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.0.tgz", + "integrity": "sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/better-opn": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/better-opn/-/better-opn-3.0.2.tgz", @@ -13979,6 +15650,15 @@ "node": ">=0.6" } }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -14061,6 +15741,12 @@ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "license": "MIT" }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "license": "MIT" + }, "node_modules/bplist-creator": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.1.0.tgz", @@ -14186,7 +15872,6 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -14196,7 +15881,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/buffer-from": { @@ -14900,6 +16584,77 @@ "node": ">=8" } }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "license": "MIT" + }, + "node_modules/cli-highlight/node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/cli-highlight/node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "license": "MIT" + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/cli-progress": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", @@ -15577,6 +17332,15 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", @@ -15960,6 +17724,32 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/degenerator/node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -16635,7 +18425,6 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" @@ -17404,7 +19193,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", @@ -17426,10 +19214,8 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "license": "BSD-3-Clause", "optional": true, - "peer": true, "engines": { "node": ">=0.10.0" } @@ -18388,7 +20174,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -18418,7 +20203,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -20855,7 +22639,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", @@ -20876,7 +22659,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, "license": "MIT", "dependencies": { "pump": "^3.0.0" @@ -20977,6 +22759,41 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fast-xml-builder": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz", + "integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.1.3" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.5.8", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz", + "integrity": "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "fast-xml-builder": "^1.1.4", + "path-expression-matcher": "^1.2.0", + "strnum": "^2.2.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -21040,7 +22857,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, "license": "MIT", "dependencies": { "pend": "~1.2.0" @@ -21063,6 +22879,38 @@ } } }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/fetch-blob/node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, "node_modules/fetch-retry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/fetch-retry/-/fetch-retry-4.1.1.tgz", @@ -21116,6 +22964,24 @@ "node": ">=16.0.0" } }, + "node_modules/file-type": { + "version": "21.3.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", + "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", + "license": "MIT", + "dependencies": { + "@tokenizer/inflate": "^0.4.1", + "strtok3": "^10.3.4", + "token-types": "^6.1.1", + "uint8array-extras": "^1.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, "node_modules/filelist": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", @@ -21505,6 +23371,18 @@ "node": ">= 12.20" } }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -21666,6 +23544,83 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gaxios": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", + "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gaxios/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/gaxios/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/gaxios/node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/generator-function": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", @@ -21693,6 +23648,18 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -21820,6 +23787,20 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "node_modules/get-uri": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", + "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/getenv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/getenv/-/getenv-1.0.0.tgz", @@ -21997,6 +23978,53 @@ "integrity": "sha512-YSwLaGMOgSBx9roJlNLL12c+FRiw7VECphinc6mGucphc/ZxTHgdEz6gmJqH6NOzYEd/yr64hwjom5pZ+tJVpg==", "dev": true }, + "node_modules/google-auth-library": { + "version": "10.6.2", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", + "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-auth-library/node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-auth-library/node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -22285,6 +24313,15 @@ "hermes-estree": "0.29.1" } }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -24368,6 +26405,15 @@ "node": ">=6" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -24395,6 +26441,19 @@ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "license": "(AFL-2.1 OR BSD-3-Clause)" }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -24632,6 +26691,17 @@ "typescript": ">=5.0.4 <7" } }, + "node_modules/koffi": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/koffi/-/koffi-2.16.1.tgz", + "integrity": "sha512-0Ie6CfD026dNfWSosDw9dPxPzO9Rlyo0N8m5r05S8YjytIpuilzMFDMY4IDy/8xQsTwpuVinhncD+S8n3bcYZQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, "node_modules/lan-network": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/lan-network/-/lan-network-0.1.7.tgz", @@ -25052,6 +27122,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -25251,6 +27327,18 @@ "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", "license": "BSD-2-Clause" }, + "node_modules/marked": { + "version": "15.0.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", + "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/marky": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", @@ -26978,6 +29066,15 @@ "integrity": "sha512-SrQrok4CATudVzBS7coSz26QRSmlK9TzzoFbeKfcPBUFPjcQM9Rqvr/DlJkOrwI/0KcgvMub1n1g5Jt9EgRn4A==", "license": "MIT" }, + "node_modules/netmask": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", + "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/node-abi": { "version": "4.28.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.28.0.tgz", @@ -27845,6 +29942,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -27854,6 +29973,73 @@ "node": ">=6" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -28004,6 +30190,12 @@ "node": ">= 0.8" } }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "license": "MIT" + }, "node_modules/password-prompt": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/password-prompt/-/password-prompt-1.1.3.tgz", @@ -28054,6 +30246,21 @@ "node": ">=8" } }, + "node_modules/path-expression-matcher": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -28153,43 +30360,8 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true, "license": "MIT" }, - "node_modules/pi-acp": { - "version": "0.0.24", - "resolved": "https://registry.npmjs.org/pi-acp/-/pi-acp-0.0.24.tgz", - "integrity": "sha512-iFoQLH9nd3e2fpvemFV/0SUPeT9ecGHyhBiAe1JW7kHBWfmBQREeRn7O+hQyWA7heMVv+C9CObk4HDLVRy7JaQ==", - "license": "MIT", - "dependencies": { - "@agentclientprotocol/sdk": "^0.12.0", - "zod": "^3.25.0" - }, - "bin": { - "pi-acp": "dist/index.js" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/pi-acp/node_modules/@agentclientprotocol/sdk": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.12.0.tgz", - "integrity": "sha512-V8uH/KK1t7utqyJmTA7y7DzKu6+jKFIXM+ZVouz8E55j8Ej2RV42rEvPKn3/PpBJlliI5crcGk1qQhZ7VwaepA==", - "license": "Apache-2.0", - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - } - }, - "node_modules/pi-acp/node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -28724,7 +30896,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", - "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -28736,7 +30907,6 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, "license": "ISC" }, "node_modules/property-information": { @@ -28749,6 +30919,30 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/protobufjs": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", + "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -28762,11 +30956,73 @@ "node": ">= 0.10" } }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true, "license": "MIT" }, "node_modules/psl": { @@ -30340,7 +32596,6 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -31316,7 +33571,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6.0.0", @@ -31340,7 +33594,6 @@ "version": "2.8.7", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "dev": true, "license": "MIT", "dependencies": { "ip-address": "^10.0.1", @@ -31355,7 +33608,6 @@ "version": "8.0.5", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -31370,7 +33622,6 @@ "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -31645,7 +33896,6 @@ "version": "3.10.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, "license": "MIT" }, "node_modules/stop-iteration-iterator": { @@ -31978,6 +34228,34 @@ "dev": true, "license": "MIT" }, + "node_modules/strnum": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz", + "integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/strtok3": { + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/structured-headers": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/structured-headers/-/structured-headers-0.4.1.tgz", @@ -32630,6 +34908,24 @@ "node": ">=0.6" } }, + "node_modules/token-types": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", + "license": "MIT", + "dependencies": { + "@borewit/text-codec": "^0.2.1", + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -32735,6 +35031,12 @@ "utf8-byte-length": "^1.0.1" } }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", @@ -33158,6 +35460,18 @@ "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", "license": "MIT" }, + "node_modules/uint8array-extras": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unbash": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/unbash/-/unbash-2.2.0.tgz", @@ -34685,7 +36999,6 @@ "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -34704,7 +37017,6 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", @@ -34733,6 +37045,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/youch": { "version": "4.1.0-beta.10", "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.10.tgz", @@ -35339,6 +37663,7 @@ "@getpaseo/highlight": "0.1.60-rc.1", "@getpaseo/relay": "0.1.60-rc.1", "@isaacs/ttlcache": "^2.1.4", + "@mariozechner/pi-coding-agent": "^0.67.68", "@modelcontextprotocol/sdk": "^1.20.1", "@opencode-ai/sdk": "1.2.6", "@sctg/sentencepiece-js": "^1.1.0", @@ -35355,7 +37680,6 @@ "onnxruntime-node": "^1.23.0", "openai": "^4.20.0", "p-limit": "^7.3.0", - "pi-acp": "^0.0.24", "pino": "^10.2.0", "pino-pretty": "^13.1.3", "qrcode": "^1.5.4", @@ -35385,6 +37709,26 @@ "vitest": "^3.2.4" } }, + "packages/server/node_modules/@anthropic-ai/sdk": { + "version": "0.90.0", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.90.0.tgz", + "integrity": "sha512-MzZtPabJF1b0FTDl6Z6H5ljphPwACLGP13lu8MTiB8jXaW/YXlpOp+Po2cVou3MPM5+f5toyLnul9whKCy7fBg==", + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, "packages/server/node_modules/@isaacs/ttlcache": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-2.1.4.tgz", @@ -35394,6 +37738,147 @@ "node": ">=12" } }, + "packages/server/node_modules/@mariozechner/pi-agent-core": { + "version": "0.67.68", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-agent-core/-/pi-agent-core-0.67.68.tgz", + "integrity": "sha512-anwFuzeUL7Qjbyih4DWY7w1zrOTrBxaz1L6+duLUuuzpHOun0EiP4KWIGTXPT5oJA7ZaeRNTyXJ7PlWfGQG33g==", + "license": "MIT", + "dependencies": { + "@mariozechner/pi-ai": "^0.67.68" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/server/node_modules/@mariozechner/pi-ai": { + "version": "0.67.68", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-ai/-/pi-ai-0.67.68.tgz", + "integrity": "sha512-DWWQmcb3IV3mbGXmzYBScfKA6kA52n/stY029eiBikrIxVT7DGLG6n7KSvTA2R4qBSgi1iFL3nGHtwxmtIn6Lg==", + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "^0.90.0", + "@aws-sdk/client-bedrock-runtime": "^3.1030.0", + "@google/genai": "^1.40.0", + "@mistralai/mistralai": "^2.2.0", + "@sinclair/typebox": "^0.34.41", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "chalk": "^5.6.2", + "openai": "6.26.0", + "partial-json": "^0.1.7", + "proxy-agent": "^6.5.0", + "undici": "^7.19.1", + "zod-to-json-schema": "^3.24.6" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "packages/server/node_modules/@mariozechner/pi-ai/node_modules/openai": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", + "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "packages/server/node_modules/@mariozechner/pi-coding-agent": { + "version": "0.67.68", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-coding-agent/-/pi-coding-agent-0.67.68.tgz", + "integrity": "sha512-Bai2yUBpgjftqGvg3GNV9pxcMAatqJwQYsqM+7j39+tm+IpoW7hbMBnzXZQvykAwXIrTXpZFF5yp5ajeDI5Atg==", + "license": "MIT", + "dependencies": { + "@mariozechner/jiti": "^2.6.2", + "@mariozechner/pi-agent-core": "^0.67.68", + "@mariozechner/pi-ai": "^0.67.68", + "@mariozechner/pi-tui": "^0.67.68", + "@silvia-odwyer/photon-node": "^0.3.4", + "ajv": "^8.17.1", + "chalk": "^5.5.0", + "cli-highlight": "^2.1.11", + "diff": "^8.0.2", + "extract-zip": "^2.0.1", + "file-type": "^21.1.1", + "glob": "^13.0.1", + "hosted-git-info": "^9.0.2", + "ignore": "^7.0.5", + "marked": "^15.0.12", + "minimatch": "^10.2.3", + "proper-lockfile": "^4.1.2", + "strip-ansi": "^7.1.0", + "undici": "^7.19.1", + "uuid": "^11.1.0", + "yaml": "^2.8.2" + }, + "bin": { + "pi": "dist/cli.js" + }, + "engines": { + "node": ">=20.6.0" + }, + "optionalDependencies": { + "@mariozechner/clipboard": "^0.3.2" + } + }, + "packages/server/node_modules/@mariozechner/pi-coding-agent/node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "packages/server/node_modules/@mariozechner/pi-tui": { + "version": "0.67.68", + "resolved": "https://registry.npmjs.org/@mariozechner/pi-tui/-/pi-tui-0.67.68.tgz", + "integrity": "sha512-RhcMaGz88lNOm5+9yx+YCIfXZALLbMxB2cwsoHzyOzs+OZAItw8tz6xJZPAnX0RHY+ENQEGMMDY9TF6pxxnkbA==", + "license": "MIT", + "dependencies": { + "@types/mime-types": "^2.1.4", + "chalk": "^5.5.0", + "get-east-asian-width": "^1.3.0", + "marked": "^15.0.12", + "mime-types": "^3.0.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "optionalDependencies": { + "koffi": "^2.9.0" + } + }, + "packages/server/node_modules/@mistralai/mistralai": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.2.0.tgz", + "integrity": "sha512-JQUGIXjFWnw/J9LpTSf/ZXwVW3Sh8FBAcfTo5QvAHqkl4CfSiIwnjRJhMoAFcP6ncCe84YPU1ncDGX+p3OXnfg==", + "license": "Apache-2.0", + "dependencies": { + "ws": "^8.18.0", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "^3.25.0" + } + }, "packages/server/node_modules/@modelcontextprotocol/sdk": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.20.1.tgz", @@ -35481,6 +37966,18 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "license": "MIT" }, + "packages/server/node_modules/@sinclair/typebox": { + "version": "0.34.49", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", + "integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==", + "license": "MIT" + }, + "packages/server/node_modules/@types/mime-types": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", + "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", + "license": "MIT" + }, "packages/server/node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -35510,6 +38007,23 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "packages/server/node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, "packages/server/node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", @@ -35522,6 +38036,15 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "packages/server/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, "packages/server/node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -35542,6 +38065,30 @@ "node": ">=18" } }, + "packages/server/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "packages/server/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "packages/server/node_modules/content-disposition": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", @@ -35589,6 +38136,44 @@ "node": ">= 0.8" } }, + "packages/server/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "packages/server/node_modules/hosted-git-info": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", + "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "packages/server/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, "packages/server/node_modules/isexe": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", @@ -35598,6 +38183,15 @@ "node": ">=18" } }, + "packages/server/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "packages/server/node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", @@ -35631,6 +38225,21 @@ "node": ">= 0.6" } }, + "packages/server/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "packages/server/node_modules/negotiator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", @@ -35655,6 +38264,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/server/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "packages/server/node_modules/raw-body": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", diff --git a/packages/app/src/app/_layout.tsx b/packages/app/src/app/_layout.tsx index f35616127..c0bd3a0e7 100644 --- a/packages/app/src/app/_layout.tsx +++ b/packages/app/src/app/_layout.tsx @@ -867,18 +867,18 @@ export default function RootLayout() { - - - - + + + + - - - - + + + + diff --git a/packages/app/src/components/agent-status-bar.tsx b/packages/app/src/components/agent-status-bar.tsx index 5f501ab8a..d4540dc0e 100644 --- a/packages/app/src/components/agent-status-bar.tsx +++ b/packages/app/src/components/agent-status-bar.tsx @@ -52,6 +52,8 @@ import { resolveAgentModelSelection, } from "@/components/agent-status-bar.utils"; import { isWeb as platformIsWeb } from "@/constants/platform"; +import { useToast } from "@/contexts/toast-context"; +import { toErrorMessage } from "@/utils/error-messages"; type StatusOption = { id: string; @@ -863,6 +865,7 @@ export const AgentStatusBar = memo(function AgentStatusBar({ (a, b) => a === b || JSON.stringify(a) === JSON.stringify(b), ); const client = useSessionStore((state) => state.sessions[serverId]?.client ?? null); + const toast = useToast(); const { entries: snapshotEntries, @@ -953,6 +956,7 @@ export const AgentStatusBar = memo(function AgentStatusBar({ } void client.setAgentMode(agentId, modeId).catch((error) => { console.warn("[AgentStatusBar] setAgentMode failed", error); + toast.error(toErrorMessage(error)); }); }} modelOptions={modelOptions} @@ -974,6 +978,7 @@ export const AgentStatusBar = memo(function AgentStatusBar({ }); void client.setAgentModel(agentId, modelId).catch((error) => { console.warn("[AgentStatusBar] setAgentModel failed", error); + toast.error(toErrorMessage(error)); }); }} favoriteKeys={favoriteKeys} @@ -1009,6 +1014,7 @@ export const AgentStatusBar = memo(function AgentStatusBar({ } void client.setAgentThinkingOption(agentId, thinkingOptionId).catch((error) => { console.warn("[AgentStatusBar] setAgentThinkingOption failed", error); + toast.error(toErrorMessage(error)); }); }} features={agent.features} @@ -1031,6 +1037,7 @@ export const AgentStatusBar = memo(function AgentStatusBar({ }); void client.setAgentFeature(agentId, featureId, value).catch((error) => { console.warn("[AgentStatusBar] setAgentFeature failed", error); + toast.error(toErrorMessage(error)); }); }} isModelLoading={snapshotIsLoading} diff --git a/packages/app/src/contexts/session-context.tsx b/packages/app/src/contexts/session-context.tsx index c53d084ee..63238e22d 100644 --- a/packages/app/src/contexts/session-context.tsx +++ b/packages/app/src/contexts/session-context.tsx @@ -57,6 +57,8 @@ import { splitComposerAttachmentsForSubmit } from "@/components/composer-attachm import { reconcilePreviousAgentStatuses } from "@/contexts/session-status-tracking"; import { patchWorkspaceScripts } from "@/contexts/session-workspace-scripts"; import { isNative } from "@/constants/platform"; +import { useToast } from "@/contexts/toast-context"; +import { toErrorMessage } from "@/utils/error-messages"; // Re-export types from session-store and draft-store for backward compatibility export type { DraftInput } from "@/stores/draft-store"; @@ -258,6 +260,7 @@ function SessionProviderInternal({ children, serverId, client }: SessionProvider const voiceAudioEngine = useVoiceAudioEngineOptional(); const queryClient = useQueryClient(); const isConnected = useHostRuntimeIsConnected(serverId); + const toast = useToast(); // Zustand store actions const initializeSession = useSessionStore((state) => state.initializeSession); @@ -1769,9 +1772,10 @@ function SessionProviderInternal({ children, serverId, client }: SessionProvider } void client.setAgentMode(agentId, modeId).catch((error) => { console.error("[Session] Failed to set agent mode:", error); + toast.error(toErrorMessage(error)); }); }, - [client], + [client, toast], ); const setAgentModel = useCallback( @@ -1782,9 +1786,10 @@ function SessionProviderInternal({ children, serverId, client }: SessionProvider } void client.setAgentModel(agentId, modelId).catch((error) => { console.error("[Session] Failed to set agent model:", error); + toast.error(toErrorMessage(error)); }); }, - [client], + [client, toast], ); const setAgentThinkingOption = useCallback( @@ -1795,9 +1800,10 @@ function SessionProviderInternal({ children, serverId, client }: SessionProvider } void client.setAgentThinkingOption(agentId, thinkingOptionId).catch((error) => { console.error("[Session] Failed to set agent thinking option:", error); + toast.error(toErrorMessage(error)); }); }, - [client], + [client, toast], ); const respondToPermission = useCallback( diff --git a/packages/server/package.json b/packages/server/package.json index 7f3d68535..1f32a0cc9 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -64,6 +64,7 @@ "@getpaseo/relay": "0.1.60-rc.1", "@isaacs/ttlcache": "^2.1.4", "@modelcontextprotocol/sdk": "^1.20.1", + "@mariozechner/pi-coding-agent": "^0.67.68", "@opencode-ai/sdk": "1.2.6", "@sctg/sentencepiece-js": "^1.1.0", "@xterm/headless": "^6.0.0", @@ -79,7 +80,6 @@ "onnxruntime-node": "^1.23.0", "openai": "^4.20.0", "p-limit": "^7.3.0", - "pi-acp": "^0.0.24", "pino": "^10.2.0", "pino-pretty": "^13.1.3", "qrcode": "^1.5.4", diff --git a/packages/server/src/server/agent/provider-registry.test.ts b/packages/server/src/server/agent/provider-registry.test.ts index 8d669c1bd..445b121c2 100644 --- a/packages/server/src/server/agent/provider-registry.test.ts +++ b/packages/server/src/server/agent/provider-registry.test.ts @@ -226,8 +226,8 @@ vi.mock("./providers/opencode-agent.js", () => ({ }, })); -vi.mock("./providers/pi-acp-agent.js", () => ({ - PiACPAgentClient: class PiACPAgentClient { +vi.mock("./providers/pi-direct-agent.js", () => ({ + PiDirectAgentClient: class PiDirectAgentClient { readonly capabilities = { supportsStreaming: true, supportsSessionPersistence: true, diff --git a/packages/server/src/server/agent/provider-registry.ts b/packages/server/src/server/agent/provider-registry.ts index a7d383078..d775c8b33 100644 --- a/packages/server/src/server/agent/provider-registry.ts +++ b/packages/server/src/server/agent/provider-registry.ts @@ -25,7 +25,7 @@ import { CodexAppServerAgentClient } from "./providers/codex-app-server-agent.js import { CopilotACPAgentClient } from "./providers/copilot-acp-agent.js"; import { GenericACPAgentClient } from "./providers/generic-acp-agent.js"; import { OpenCodeAgentClient, OpenCodeServerManager } from "./providers/opencode-agent.js"; -import { PiACPAgentClient } from "./providers/pi-acp-agent.js"; +import { PiDirectAgentClient } from "./providers/pi-direct-agent.js"; import { AGENT_PROVIDER_DEFINITIONS, BUILTIN_PROVIDER_IDS, @@ -75,7 +75,7 @@ const PROVIDER_CLIENT_FACTORIES: Record = { }), opencode: (logger, runtimeSettings) => new OpenCodeAgentClient(logger, runtimeSettings), pi: (logger, runtimeSettings) => - new PiACPAgentClient({ + new PiDirectAgentClient({ logger, runtimeSettings, }), diff --git a/packages/server/src/server/agent/providers/acp-agent.test.ts b/packages/server/src/server/agent/providers/acp-agent.test.ts index f413a412b..8d8112c50 100644 --- a/packages/server/src/server/agent/providers/acp-agent.test.ts +++ b/packages/server/src/server/agent/providers/acp-agent.test.ts @@ -8,7 +8,7 @@ import { deriveModesFromACP, mapACPUsage, } from "./acp-agent.js"; -import { transformPiModels, transformPiSessionResponse, wrapPiSession } from "./pi-acp-agent.js"; +import { transformPiModels } from "./pi-direct-agent.js"; import { createTestLogger } from "../../../test-utils/test-logger.js"; function createSession(): ACPAgentSession { @@ -246,7 +246,7 @@ describe("ACPAgentClient modelTransformer", () => { const client = new TestACPAgentClient({ provider: "pi", logger: createTestLogger(), - defaultCommand: ["pi-acp"], + defaultCommand: ["test-acp"], modelTransformer: transformPiModels, }); @@ -270,23 +270,10 @@ describe("ACPAgentClient sessionResponseTransformer", () => { const response: SessionStateResponse = { sessionId: "session-1", modes: { - availableModes: [ - { id: "off", name: "Thinking: Off", description: "No extra reasoning" }, - { id: "medium", name: "Thinking: Medium", description: "Balanced reasoning" }, - { id: "high", name: "Thinking: High", description: "Deeper reasoning" }, - ], - currentModeId: "medium", - }, - models: { - availableModels: [ - { - modelId: "openrouter/openai/gpt-4.1-mini", - name: "openrouter/openai/gpt-4.1-mini", - description: null, - }, - ], - currentModelId: "openrouter/openai/gpt-4.1-mini", + availableModes: [{ id: "raw", name: "Raw", description: "Before transform" }], + currentModeId: "raw", }, + models: null, configOptions: [], }; @@ -302,48 +289,26 @@ describe("ACPAgentClient sessionResponseTransformer", () => { protected override async closeProbe(): Promise {} } - test("remaps Pi thinking modes into thinking options for list probes", async () => { + test("applies sessionResponseTransformer before deriving list probe modes", async () => { const client = new TestACPAgentClient({ - provider: "pi", + provider: "claude-acp", logger: createTestLogger(), - defaultCommand: ["pi-acp"], + defaultCommand: ["claude", "--acp"], defaultModes: [], - modelTransformer: transformPiModels, - sessionResponseTransformer: transformPiSessionResponse, + sessionResponseTransformer: (response) => ({ + ...response, + modes: { + availableModes: [{ id: "review", name: "Review", description: "After transform" }], + currentModeId: "review", + }, + }), }); - await expect(client.listModes()).resolves.toEqual([]); - await expect(client.listModels()).resolves.toEqual([ + await expect(client.listModes()).resolves.toEqual([ { - provider: "pi", - id: "openrouter/openai/gpt-4.1-mini", - label: "gpt-4.1-mini", - description: "openrouter/openai/gpt-4.1-mini", - isDefault: true, - thinkingOptions: [ - { - id: "off", - label: "Off", - description: "No extra reasoning", - isDefault: false, - metadata: undefined, - }, - { - id: "medium", - label: "Medium", - description: "Balanced reasoning", - isDefault: true, - metadata: undefined, - }, - { - id: "high", - label: "High", - description: "Deeper reasoning", - isDefault: false, - metadata: undefined, - }, - ], - defaultThinkingOptionId: "medium", + id: "review", + label: "Review", + description: "After transform", }, ]); }); @@ -384,7 +349,7 @@ describe("ACPAgentClient listModes", () => { const client = new TestACPAgentClient({ provider: "pi", logger: createTestLogger(), - defaultCommand: ["pi-acp"], + defaultCommand: ["test-acp"], defaultModes: [], }); @@ -456,21 +421,19 @@ describe("ACPAgentSession slash commands", () => { test("waits for async available_commands_update when enabled", async () => { const session = new ACPAgentSession( { - provider: "pi", + provider: "claude-acp", cwd: "/tmp/paseo-acp-test", }, { - provider: "pi", + provider: "claude-acp", logger: createTestLogger(), - defaultCommand: ["pi-acp"], + defaultCommand: ["claude", "--acp"], defaultModes: [], - modelTransformer: transformPiModels, - sessionResponseTransformer: transformPiSessionResponse, capabilities: { supportsStreaming: true, supportsSessionPersistence: true, supportsDynamicModes: true, - supportsMcpServers: false, + supportsMcpServers: true, supportsReasoningStream: true, supportsToolInvocations: true, }, @@ -524,158 +487,6 @@ describe("ACPAgentSession slash commands", () => { }); describe("ACPAgentSession", () => { - test("applies sessionResponseTransformer before deriving modes and thinking state", () => { - const session = new ACPAgentSession( - { - provider: "pi", - cwd: "/tmp/paseo-acp-test", - }, - { - provider: "pi", - logger: createTestLogger(), - defaultCommand: ["pi-acp"], - defaultModes: [], - modelTransformer: transformPiModels, - sessionResponseTransformer: transformPiSessionResponse, - capabilities: { - supportsStreaming: true, - supportsSessionPersistence: true, - supportsDynamicModes: true, - supportsMcpServers: false, - supportsReasoningStream: true, - supportsToolInvocations: true, - }, - }, - ); - - (session as any).applySessionState({ - sessionId: "session-1", - modes: { - availableModes: [ - { id: "low", name: "Thinking: Low", description: "Faster" }, - { id: "medium", name: "Thinking: Medium", description: "Balanced" }, - ], - currentModeId: "medium", - }, - models: { - availableModels: [ - { - modelId: "openrouter/openai/gpt-4.1-mini", - name: "openrouter/openai/gpt-4.1-mini", - description: null, - }, - ], - currentModelId: "openrouter/openai/gpt-4.1-mini", - }, - configOptions: [], - } satisfies SessionStateResponse); - - expect((session as any).availableModes).toEqual([]); - expect((session as any).thinkingOptionId).toBe("medium"); - expect((session as any).availableModels).toEqual([ - { - provider: "pi", - id: "openrouter/openai/gpt-4.1-mini", - label: "gpt-4.1-mini", - description: "openrouter/openai/gpt-4.1-mini", - isDefault: true, - thinkingOptions: [ - { - id: "low", - label: "Low", - description: "Faster", - isDefault: false, - metadata: undefined, - }, - { - id: "medium", - label: "Medium", - description: "Balanced", - isDefault: true, - metadata: undefined, - }, - ], - defaultThinkingOptionId: "medium", - }, - ]); - }); - - test("Pi session wrapper hides synthetic modes and exposes them as thinking", async () => { - const wrapped = wrapPiSession( - { - provider: "pi", - id: "session-1", - capabilities: { - supportsStreaming: true, - supportsSessionPersistence: true, - supportsDynamicModes: true, - supportsMcpServers: false, - supportsReasoningStream: true, - supportsToolInvocations: true, - }, - features: [ - { - type: "select", - id: "thought_level", - label: "Thinking", - value: "medium", - options: [ - { id: "low", label: "Low" }, - { id: "medium", label: "Medium" }, - ], - }, - ], - run: vi.fn(), - startTurn: vi.fn(), - subscribe: vi.fn(() => () => {}), - streamHistory: async function* () {}, - getRuntimeInfo: vi.fn(async () => ({ - provider: "pi", - sessionId: "session-1", - model: "gpt-4.1-mini", - thinkingOptionId: null, - modeId: "xhigh", - })), - getAvailableModes: vi.fn(async () => [{ id: "xhigh", label: "xhigh" }]), - getCurrentMode: vi.fn(async () => "xhigh"), - setMode: vi.fn(), - getPendingPermissions: vi.fn(() => []), - respondToPermission: vi.fn(), - describePersistence: vi.fn(() => null), - interrupt: vi.fn(), - close: vi.fn(), - setThinkingOption: vi.fn(), - }, - { - provider: "pi", - cwd: "/tmp/paseo-acp-test", - thinkingOptionId: "medium", - }, - ); - - await expect(wrapped.getAvailableModes()).resolves.toEqual([]); - await expect(wrapped.getCurrentMode()).resolves.toBeNull(); - await expect(wrapped.getRuntimeInfo()).resolves.toEqual({ - provider: "pi", - sessionId: "session-1", - model: "gpt-4.1-mini", - thinkingOptionId: "xhigh", - modeId: null, - }); - expect(wrapped.features).toEqual([ - { - type: "select", - id: "thought_level", - label: "Thinking", - value: "xhigh", - options: [ - { id: "low", label: "Low" }, - { id: "medium", label: "Medium" }, - ], - }, - ]); - }); - test("emits assistant and reasoning chunks as deltas while user chunks stay accumulated", async () => { const session = createSession(); const events: Array<{ type: string; item?: { type: string; text?: string } }> = []; @@ -819,55 +630,4 @@ describe("ACPAgentSession", () => { }); expect((session as any).activeForegroundTurnId).toBeNull(); }); - - test("auto-approves Copilot ACP permissions in autopilot mode without emitting prompt events", async () => { - const session = new ACPAgentSession( - { - provider: "copilot", - cwd: "/tmp/paseo-acp-test", - modeId: "https://agentclientprotocol.com/protocol/session-modes#autopilot", - }, - { - provider: "copilot", - logger: createTestLogger(), - defaultCommand: ["copilot", "--acp"], - defaultModes: [], - capabilities: { - supportsStreaming: true, - supportsSessionPersistence: true, - supportsDynamicModes: true, - supportsMcpServers: true, - supportsReasoningStream: true, - supportsToolInvocations: true, - }, - }, - ); - - const events: Array<{ type: string }> = []; - session.subscribe((event) => { - events.push(event as { type: string }); - }); - - const response = await session.requestPermission({ - toolCall: { - toolCallId: "tool-1", - title: "Edit file", - kind: "edit", - status: "pending", - } as any, - options: [ - { optionId: "allow-once", name: "Allow Once", kind: "allow_once" }, - { optionId: "reject-once", name: "Reject Once", kind: "reject_once" }, - ], - } as any); - - expect(response).toEqual({ - outcome: { - outcome: "selected", - optionId: "allow-once", - }, - }); - expect(session.getPendingPermissions()).toEqual([]); - expect(events.find((event) => event.type === "permission_requested")).toBeUndefined(); - }); }); diff --git a/packages/server/src/server/agent/providers/claude-agent.ts b/packages/server/src/server/agent/providers/claude-agent.ts index de7c85205..0d3203e5d 100644 --- a/packages/server/src/server/agent/providers/claude-agent.ts +++ b/packages/server/src/server/agent/providers/claude-agent.ts @@ -778,7 +778,7 @@ class TimelineAssembler { runId: string | null, messageIdHint: string | null, ): AgentTimelineItem[] { - const event = message.event as Record; + const event = message.event as unknown as Record; const eventType = readTrimmedString(event.type); const streamEventMessageId = this.readMessageIdFromStreamEvent(event) ?? messageIdHint; @@ -2226,7 +2226,14 @@ class ClaudeAgentSession implements AgentSession { private toSdkUserMessage(prompt: AgentPromptInput): SDKUserMessage { const content: Array< | { type: "text"; text: string } - | { type: "image"; source: { type: "base64"; media_type: string; data: string } } + | { + type: "image"; + source: { + type: "base64"; + media_type: "image/jpeg" | "image/png" | "image/gif" | "image/webp"; + data: string; + }; + } > = []; if (Array.isArray(prompt)) { for (const chunk of prompt) { @@ -2237,7 +2244,7 @@ class ClaudeAgentSession implements AgentSession { type: "image", source: { type: "base64", - media_type: chunk.mimeType, + media_type: chunk.mimeType as "image/jpeg" | "image/png" | "image/gif" | "image/webp", data: chunk.data, }, }); diff --git a/packages/server/src/server/agent/providers/pi-acp-agent.ts b/packages/server/src/server/agent/providers/pi-acp-agent.ts deleted file mode 100644 index 4260f9524..000000000 --- a/packages/server/src/server/agent/providers/pi-acp-agent.ts +++ /dev/null @@ -1,406 +0,0 @@ -import { createRequire } from "node:module"; -import { existsSync } from "node:fs"; -import { join } from "node:path"; -import { homedir } from "node:os"; -import type { Logger } from "pino"; -import type { ClientSideConnection, SessionConfigOption, ToolKind } from "@agentclientprotocol/sdk"; - -import type { - AgentLaunchContext, - AgentCapabilityFlags, - AgentFeature, - AgentMode, - AgentModelDefinition, - AgentPermissionRequest, - AgentPermissionResponse, - AgentPersistenceHandle, - AgentPromptInput, - AgentRunOptions, - AgentRunResult, - AgentRuntimeInfo, - AgentSession, - AgentSessionConfig, - AgentSlashCommand, - AgentStreamEvent, - AgentFeatureSelect, -} from "../agent-sdk-types.js"; -import type { ProviderRuntimeSettings } from "../provider-launch-config.js"; -import { findExecutable, isCommandAvailable } from "../../../utils/executable.js"; -import { ACPAgentClient, type ACPToolSnapshot, type SessionStateResponse } from "./acp-agent.js"; -import { - formatDiagnosticStatus, - formatProviderDiagnostic, - formatProviderDiagnosticError, - resolveBinaryVersion, - toDiagnosticErrorMessage, -} from "./diagnostic-utils.js"; - -const require = createRequire(import.meta.url); -const resolvedPiAcpPath = require.resolve("pi-acp"); - -const PI_CAPABILITIES: AgentCapabilityFlags = { - supportsStreaming: true, - supportsSessionPersistence: true, - supportsDynamicModes: true, - supportsMcpServers: false, - supportsReasoningStream: true, - supportsToolInvocations: true, -}; - -// Pi tool kind corrections: pi-acp maps 'bash' to kind 'other' instead of 'execute'. -const PI_TOOL_KIND_MAP: Record = { - bash: "execute", -}; - -type PiACPAgentClientOptions = { - logger: Logger; - runtimeSettings?: ProviderRuntimeSettings; -}; - -function normalizePiModelLabel(label: string): string { - return label.trim().replace(/[_\s]+/g, " "); -} - -export function transformPiModels(models: AgentModelDefinition[]): AgentModelDefinition[] { - return models.map((model) => { - if (!model.label.includes("/")) { - return model; - } - - const segments = model.label.split("/").filter((segment) => segment.length > 0); - const rawLabel = segments.at(-1); - if (!rawLabel) { - return model; - } - - return { - ...model, - label: normalizePiModelLabel(rawLabel), - description: model.description ?? model.label, - }; - }); -} - -function transformPiToolSnapshot(snapshot: ACPToolSnapshot): ACPToolSnapshot { - if (snapshot.kind === "other" && snapshot.title && PI_TOOL_KIND_MAP[snapshot.title]) { - return { ...snapshot, kind: PI_TOOL_KIND_MAP[snapshot.title] }; - } - return snapshot; -} - -/** - * Pi-acp reports thinking levels (off/minimal/low/medium/high/xhigh) as ACP - * session modes rather than as configOptions with category 'thought_level'. - * This transformer remaps them so the base ACP class treats them as thinking - * options instead of permission modes. - */ -export function transformPiSessionResponse(response: SessionStateResponse): SessionStateResponse { - const modes = response.modes; - if (!modes?.availableModes?.length) { - return response; - } - - const thinkingOption: SessionConfigOption = { - id: "thought_level", - name: "Thinking", - type: "select", - category: "thought_level", - currentValue: modes.currentModeId ?? "medium", - options: modes.availableModes.map((mode) => ({ - value: mode.id, - name: mode.name.replace(/^Thinking:\s*/i, ""), - description: mode.description, - })), - }; - - return { - ...response, - modes: undefined, - configOptions: [thinkingOption, ...(response.configOptions ?? [])], - }; -} - -function isThoughtLevelFeature(feature: AgentFeature): feature is AgentFeatureSelect { - return feature.type === "select" && feature.id === "thought_level"; -} - -function normalizePiFeatures( - features: AgentFeature[] | undefined, - thinkingOptionId: string | null | undefined, -): AgentFeature[] | undefined { - if (!features) { - return features; - } - - return features.map((feature) => { - if (!isThoughtLevelFeature(feature)) { - return feature; - } - - return { - ...feature, - value: thinkingOptionId ?? feature.value, - }; - }); -} - -class PiACPAgentSession implements AgentSession { - readonly provider: AgentSession["provider"]; - readonly capabilities: AgentSession["capabilities"]; - - get id(): string | null { - return this.inner.id; - } - - get features(): AgentFeature[] | undefined { - return normalizePiFeatures(this.inner.features, this.thinkingOptionId); - } - - private thinkingOptionId: string | null; - - constructor( - private readonly inner: AgentSession, - config: AgentSessionConfig, - ) { - this.provider = inner.provider; - this.capabilities = inner.capabilities; - this.thinkingOptionId = config.thinkingOptionId ?? null; - } - - async run(prompt: AgentPromptInput, options?: AgentRunOptions): Promise { - return this.inner.run(prompt, options); - } - - async startTurn( - prompt: AgentPromptInput, - options?: AgentRunOptions, - ): Promise<{ turnId: string }> { - return this.inner.startTurn(prompt, options); - } - - subscribe(callback: (event: AgentStreamEvent) => void): () => void { - return this.inner.subscribe(callback); - } - - async *streamHistory(): AsyncGenerator { - yield* this.inner.streamHistory(); - } - - async getRuntimeInfo(): Promise { - const runtimeInfo = await this.inner.getRuntimeInfo(); - const thinkingOptionId = - runtimeInfo.modeId ?? runtimeInfo.thinkingOptionId ?? this.thinkingOptionId; - this.thinkingOptionId = thinkingOptionId ?? null; - return { - ...runtimeInfo, - modeId: null, - thinkingOptionId: thinkingOptionId ?? null, - }; - } - - async getAvailableModes(): Promise { - return []; - } - - async getCurrentMode(): Promise { - return null; - } - - async setMode(modeId: string): Promise { - void modeId; - throw new Error("Pi does not expose selectable modes"); - } - - getPendingPermissions(): AgentPermissionRequest[] { - return this.inner.getPendingPermissions(); - } - - async respondToPermission(requestId: string, response: AgentPermissionResponse): Promise { - await this.inner.respondToPermission(requestId, response); - } - - describePersistence(): AgentPersistenceHandle | null { - return this.inner.describePersistence(); - } - - async interrupt(): Promise { - await this.inner.interrupt(); - } - - async close(): Promise { - await this.inner.close(); - } - - async listCommands(): Promise { - return this.inner.listCommands ? this.inner.listCommands() : []; - } - - async setModel(modelId: string | null): Promise { - if (this.inner.setModel) { - await this.inner.setModel(modelId); - } - } - - async setThinkingOption(thinkingOptionId: string | null): Promise { - this.thinkingOptionId = thinkingOptionId ?? null; - if (this.inner.setThinkingOption) { - await this.inner.setThinkingOption(thinkingOptionId); - } - } - - async setFeature(featureId: string, value: unknown): Promise { - if (!this.inner.setFeature) { - throw new Error("Agent session does not support setting features"); - } - await this.inner.setFeature(featureId, value); - } -} - -export function wrapPiSession( - session: AgentSession, - config: Pick, -): AgentSession { - return new PiACPAgentSession(session, config); -} - -export class PiACPAgentClient extends ACPAgentClient { - constructor(options: PiACPAgentClientOptions) { - super({ - provider: "pi", - logger: options.logger, - runtimeSettings: options.runtimeSettings, - defaultCommand: [process.execPath, resolvedPiAcpPath], - defaultModes: [], - modelTransformer: transformPiModels, - sessionResponseTransformer: transformPiSessionResponse, - toolSnapshotTransformer: transformPiToolSnapshot, - thinkingOptionWriter: async ( - connection: ClientSideConnection, - sessionId: string, - thinkingOptionId: string, - ) => { - await connection.setSessionMode({ sessionId, modeId: thinkingOptionId }); - }, - capabilities: PI_CAPABILITIES, - waitForInitialCommands: true, - initialCommandsWaitTimeoutMs: 1500, - }); - } - - override async createSession( - config: AgentSessionConfig, - launchContext?: AgentLaunchContext, - ): Promise { - const session = await super.createSession(config, launchContext); - return wrapPiSession(session, config); - } - - override async resumeSession( - handle: AgentPersistenceHandle, - overrides?: Partial, - launchContext?: AgentLaunchContext, - ): Promise { - const session = await super.resumeSession(handle, overrides, launchContext); - return wrapPiSession(session, { - provider: "pi", - cwd: overrides?.cwd ?? process.cwd(), - thinkingOptionId: overrides?.thinkingOptionId, - }); - } - - override async isAvailable(): Promise { - if (!existsSync(resolvedPiAcpPath)) { - return false; - } - if (!(await isCommandAvailable(process.env.PI_ACP_PI_COMMAND ?? "pi"))) { - return false; - } - return ( - Boolean(process.env.OPENAI_API_KEY) || - Boolean(process.env.ANTHROPIC_API_KEY) || - Boolean(process.env.OPENROUTER_API_KEY) || - existsSync(join(homedir(), ".pi", "agent", "auth.json")) - ); - } - - async getDiagnostic(): Promise<{ diagnostic: string }> { - try { - const piCommand = process.env.PI_ACP_PI_COMMAND ?? "pi"; - const piCliPath = await findExecutable(piCommand); - const piVersion = piCliPath ? await resolveBinaryVersion(piCliPath) : "unknown"; - const authConfigPath = join(homedir(), ".pi", "agent", "auth.json"); - const available = await this.isAvailable(); - let modelsValue = "Not checked"; - let status = formatDiagnosticStatus(available); - - if (available) { - try { - const models = await this.listModels(); - modelsValue = String(models.length); - } catch (error) { - modelsValue = `Error - ${toDiagnosticErrorMessage(error)}`; - status = formatDiagnosticStatus(available, { - source: "model fetch", - cause: error, - }); - } - - if (!modelsValue.startsWith("Error -")) { - try { - await this.listModes(); - } catch (error) { - status = formatDiagnosticStatus(available, { - source: "mode fetch", - cause: error, - }); - } - } - } - - return { - diagnostic: formatProviderDiagnostic("Pi", [ - { - label: "pi-acp module", - value: existsSync(resolvedPiAcpPath) ? "found" : "not found", - }, - { - label: "Binary", - value: piCliPath ?? "not found", - }, - { - label: "Version", - value: piVersion, - }, - { - label: "OPENAI_API_KEY", - value: process.env.OPENAI_API_KEY ? "set" : "not set", - }, - { - label: "ANTHROPIC_API_KEY", - value: process.env.ANTHROPIC_API_KEY ? "set" : "not set", - }, - { - label: "OPENROUTER_API_KEY", - value: process.env.OPENROUTER_API_KEY ? "set" : "not set", - }, - { - label: "Auth config (~/.pi/agent/auth.json)", - value: existsSync(authConfigPath) ? "found" : "not found", - }, - { - label: "Models", - value: modelsValue, - }, - { - label: "Status", - value: status, - }, - ]), - }; - } catch (error) { - return { - diagnostic: formatProviderDiagnosticError("Pi", error), - }; - } - } -} diff --git a/packages/server/src/server/agent/providers/pi-direct-agent.ts b/packages/server/src/server/agent/providers/pi-direct-agent.ts new file mode 100644 index 000000000..66f64c925 --- /dev/null +++ b/packages/server/src/server/agent/providers/pi-direct-agent.ts @@ -0,0 +1,1442 @@ +import { randomUUID } from "node:crypto"; +import { existsSync } from "node:fs"; +import { join } from "node:path"; +import { homedir } from "node:os"; +import type { Logger } from "pino"; +import { + AuthStorage, + ModelRegistry, + SessionManager, + createAgentSession, + type AgentSession as PiAgentSession, + type AgentSessionEvent, + type BashToolInput, + type EditToolInput, + type FindToolInput, + type GrepToolInput, + type LsToolInput, + type ReadToolInput, + type ResourceLoader, + type ResolvedCommand, + type Skill, + type WriteToolInput, +} from "@mariozechner/pi-coding-agent"; +import type { ThinkingLevel } from "@mariozechner/pi-agent-core"; +import type { + Api, + ImageContent, + Model, + TextContent, + ThinkingContent, + ToolCall, +} from "@mariozechner/pi-ai"; +import { z } from "zod"; + +import type { + AgentCapabilityFlags, + AgentClient, + AgentLaunchContext, + AgentMetadata, + AgentMode, + AgentModelDefinition, + AgentPermissionRequest, + AgentPermissionResponse, + AgentPersistenceHandle, + AgentPromptInput, + AgentRunOptions, + AgentRunResult, + AgentRuntimeInfo, + AgentSession, + AgentSessionConfig, + AgentSlashCommand, + AgentStreamEvent, + AgentTimelineItem, + AgentUsage, + ListModelsOptions, + ToolCallDetail, +} from "../agent-sdk-types.js"; +import type { ProviderRuntimeSettings } from "../provider-launch-config.js"; +import { renderPromptAttachmentAsText } from "../prompt-attachments.js"; +import { findExecutable, isCommandAvailable } from "../../../utils/executable.js"; +import { + formatDiagnosticStatus, + formatProviderDiagnostic, + formatProviderDiagnosticError, + resolveBinaryVersion, + toDiagnosticErrorMessage, +} from "./diagnostic-utils.js"; + +const PI_PROVIDER = "pi"; +const DEFAULT_PI_THINKING_LEVEL: ThinkingLevel = "medium"; +const PI_BINARY_COMMAND = process.env.PI_COMMAND ?? process.env.PI_ACP_PI_COMMAND ?? "pi"; + +const PI_CAPABILITIES: AgentCapabilityFlags = { + supportsStreaming: true, + supportsSessionPersistence: true, + supportsDynamicModes: true, + supportsMcpServers: false, + supportsReasoningStream: true, + supportsToolInvocations: true, +}; + +interface PiDirectAgentClientOptions { + logger: Logger; + runtimeSettings?: ProviderRuntimeSettings; +} + +interface PiPromptPayload { + text: string; + images?: ImageContent[]; +} + +interface ToolCallOutputSummary { + output?: string; + exitCode?: number | null; +} + +interface PiModelReference { + provider?: string; + id: string; +} + +interface PiPersistenceMetadata { + cwd?: string; +} + +interface StartTurnResult { + turnId: string; +} + +interface PiToolResultObject { + output?: string; + stdout?: string; + text?: string; + content?: PiToolResultContent[]; + exitCode?: number; + code?: number; + details?: PiToolResultDetails; +} + +interface PiToolResultDetails { + diff?: string; +} + +interface PiToolResultTextContent { + type: "text"; + text: string; +} + +interface PiToolResultUnknownContent { + type: string; +} + +type PiToolResultContent = PiToolResultTextContent | PiToolResultUnknownContent; +type PiToolResult = string | PiToolResultObject | null; + +interface PiBashToolCall { + kind: "bash"; + toolName: "bash"; + args: BashToolInput; +} + +interface PiReadToolCall { + kind: "read"; + toolName: "read"; + args: ReadToolInput; +} + +interface PiEditToolCall { + kind: "edit"; + toolName: "edit"; + args: EditToolInput; +} + +interface PiWriteToolCall { + kind: "write"; + toolName: "write"; + args: WriteToolInput; +} + +interface PiFindToolCall { + kind: "find"; + toolName: "find"; + args: FindToolInput; +} + +interface PiGrepToolCall { + kind: "grep"; + toolName: "grep"; + args: GrepToolInput; +} + +interface PiLsToolCall { + kind: "ls"; + toolName: "ls"; + args: LsToolInput; +} + +interface PiUnknownToolCall { + kind: "unknown"; + toolName: string; + args: unknown | null; +} + +type PiTrackedToolCall = + | PiBashToolCall + | PiReadToolCall + | PiEditToolCall + | PiWriteToolCall + | PiFindToolCall + | PiGrepToolCall + | PiLsToolCall + | PiUnknownToolCall; + +const PI_THINKING_OPTIONS: ReadonlyArray<{ + id: ThinkingLevel; + label: string; + description: string; + isDefault?: boolean; +}> = [ + { id: "off", label: "Off", description: "No extra reasoning" }, + { id: "minimal", label: "Minimal", description: "Light reasoning" }, + { id: "low", label: "Low", description: "Faster reasoning" }, + { id: "medium", label: "Medium", description: "Balanced reasoning", isDefault: true }, + { id: "high", label: "High", description: "Deeper reasoning" }, + { id: "xhigh", label: "XHigh", description: "Maximum reasoning" }, +] as const; + +const PiPromptTextBlockSchema = z.object({ + type: z.literal("text"), + text: z.string(), +}); + +const PiToolResultTextContentSchema = z.object({ + type: z.literal("text"), + text: z.string(), +}); + +const PiToolResultUnknownContentSchema = z + .object({ + type: z.string(), + }) + .passthrough(); + +const PiToolResultContentSchema = z.union([ + PiToolResultTextContentSchema, + PiToolResultUnknownContentSchema, +]); + +const PiToolResultDetailsSchema = z + .object({ + diff: z.string().optional(), + }) + .passthrough(); + +const PiToolResultObjectSchema = z + .object({ + output: z.string().optional(), + stdout: z.string().optional(), + text: z.string().optional(), + content: z.array(PiToolResultContentSchema).optional(), + exitCode: z.number().optional(), + code: z.number().optional(), + details: PiToolResultDetailsSchema.optional(), + }) + .passthrough(); + +const PiToolResultSchema = z.union([z.string(), PiToolResultObjectSchema, z.null()]); + +const PiPersistenceMetadataSchema = z + .object({ + cwd: z.string().optional(), + }) + .passthrough(); + +const BashToolInputSchema: z.ZodType = z.object({ + command: z.string(), + timeout: z.number().optional(), +}); + +const ReadToolInputSchema: z.ZodType = z.object({ + path: z.string(), + offset: z.number().optional(), + limit: z.number().optional(), +}); + +const EditToolInputSchema: z.ZodType = z.object({ + path: z.string(), + edits: z.array( + z.object({ + oldText: z.string(), + newText: z.string(), + }), + ), +}); + +const LegacyEditToolInputSchema = z.object({ + path: z.string(), + old_string: z.string().optional(), + oldString: z.string().optional(), + new_string: z.string().optional(), + newString: z.string().optional(), +}); + +const WriteToolInputSchema: z.ZodType = z.object({ + path: z.string(), + content: z.string(), +}); + +const FindToolInputSchema: z.ZodType = z.object({ + pattern: z.string(), + path: z.string().optional(), + limit: z.number().optional(), +}); + +const GrepToolInputSchema: z.ZodType = z.object({ + pattern: z.string(), + path: z.string().optional(), + glob: z.string().optional(), + ignoreCase: z.boolean().optional(), + literal: z.boolean().optional(), + context: z.number().optional(), + limit: z.number().optional(), +}); + +const LsToolInputSchema: z.ZodType = z.object({ + path: z.string().optional(), + limit: z.number().optional(), +}); + +function normalizePiModelLabel(label: string): string { + return label.trim().replace(/[_\s]+/g, " "); +} + +export function transformPiModels(models: AgentModelDefinition[]): AgentModelDefinition[] { + return models.map((model) => { + if (!model.label.includes("/")) { + return model; + } + + const segments = model.label.split("/").filter((segment) => segment.length > 0); + const rawLabel = segments.at(-1); + if (!rawLabel) { + return model; + } + + return { + ...model, + label: normalizePiModelLabel(rawLabel), + description: model.description ?? model.label, + }; + }); +} + +function isPiThinkingLevel(value: string | null | undefined): value is ThinkingLevel { + return ( + value === "off" || + value === "minimal" || + value === "low" || + value === "medium" || + value === "high" || + value === "xhigh" + ); +} + +function normalizePiThinkingOption(value: string | null | undefined): ThinkingLevel | null { + if (!value) { + return null; + } + return isPiThinkingLevel(value) ? value : null; +} + +function toAgentUsage( + stats: ReturnType, +): AgentUsage | undefined { + const inputTokens = stats.tokens.input; + const cachedInputTokens = stats.tokens.cacheRead; + const outputTokens = stats.tokens.output; + const totalCostUsd = stats.cost; + + if (inputTokens === 0 && cachedInputTokens === 0 && outputTokens === 0 && totalCostUsd === 0) { + return undefined; + } + + return { + inputTokens, + cachedInputTokens, + outputTokens, + totalCostUsd, + }; +} + +function convertPromptInput(prompt: AgentPromptInput): PiPromptPayload { + if (typeof prompt === "string") { + return { text: prompt }; + } + + const textParts: string[] = []; + const images: ImageContent[] = []; + + for (const block of prompt) { + if (block.type === "text") { + textParts.push(block.text); + continue; + } + + if (block.type === "image") { + images.push({ + type: "image", + data: block.data, + mimeType: block.mimeType, + }); + continue; + } + + textParts.push(renderPromptAttachmentAsText(block)); + } + + const payload: PiPromptPayload = { + text: textParts.join("\n\n"), + }; + if (images.length > 0) { + payload.images = images; + } + return payload; +} + +function parseToolResult(rawResult: unknown): PiToolResult { + const parsed = PiToolResultSchema.safeParse(rawResult); + if (parsed.success) { + return parsed.data; + } + return null; +} + +function extractTextFromToolResult(result: PiToolResult): string | undefined { + if (typeof result === "string") { + return result; + } + if (!result) { + return undefined; + } + + const directText = result.output ?? result.stdout ?? result.text; + if (directText) { + return directText; + } + if (!result.content) { + return undefined; + } + + const textParts: string[] = []; + for (const block of result.content) { + if (block.type === "text" && "text" in block) { + textParts.push(block.text); + } + } + + if (textParts.length === 0) { + return undefined; + } + return textParts.join("\n"); +} + +function resolveToolCallOutput(result: PiToolResult): ToolCallOutputSummary { + if (typeof result === "string") { + return { output: result }; + } + if (!result) { + return {}; + } + + const summary: ToolCallOutputSummary = { + output: extractTextFromToolResult(result), + }; + if (typeof result.exitCode === "number") { + summary.exitCode = result.exitCode; + return summary; + } + if (typeof result.code === "number") { + summary.exitCode = result.code; + return summary; + } + summary.exitCode = null; + return summary; +} + +function normalizeLegacyEditArgs(rawArgs: unknown): EditToolInput | null { + const parsed = LegacyEditToolInputSchema.safeParse(rawArgs); + if (!parsed.success) { + return null; + } + + const oldText = parsed.data.old_string ?? parsed.data.oldString; + const newText = parsed.data.new_string ?? parsed.data.newString; + if (!oldText || newText === undefined) { + return null; + } + + return { + path: parsed.data.path, + edits: [{ oldText, newText }], + }; +} + +function parseToolArgs(toolName: string, rawArgs: unknown): PiTrackedToolCall { + if (toolName === "bash") { + const parsed = BashToolInputSchema.safeParse(rawArgs); + if (parsed.success) { + return { kind: "bash", toolName, args: parsed.data }; + } + return { kind: "unknown", toolName, args: rawArgs ?? null }; + } + + if (toolName === "read") { + const parsed = ReadToolInputSchema.safeParse(rawArgs); + if (parsed.success) { + return { kind: "read", toolName, args: parsed.data }; + } + return { kind: "unknown", toolName, args: rawArgs ?? null }; + } + + if (toolName === "edit") { + const parsed = EditToolInputSchema.safeParse(rawArgs); + if (parsed.success) { + return { kind: "edit", toolName, args: parsed.data }; + } + + const legacyArgs = normalizeLegacyEditArgs(rawArgs); + if (legacyArgs) { + return { kind: "edit", toolName, args: legacyArgs }; + } + return { kind: "unknown", toolName, args: rawArgs ?? null }; + } + + if (toolName === "write") { + const parsed = WriteToolInputSchema.safeParse(rawArgs); + if (parsed.success) { + return { kind: "write", toolName, args: parsed.data }; + } + return { kind: "unknown", toolName, args: rawArgs ?? null }; + } + + if (toolName === "find") { + const parsed = FindToolInputSchema.safeParse(rawArgs); + if (parsed.success) { + return { kind: "find", toolName, args: parsed.data }; + } + return { kind: "unknown", toolName, args: rawArgs ?? null }; + } + + if (toolName === "grep") { + const parsed = GrepToolInputSchema.safeParse(rawArgs); + if (parsed.success) { + return { kind: "grep", toolName, args: parsed.data }; + } + return { kind: "unknown", toolName, args: rawArgs ?? null }; + } + + if (toolName === "ls") { + const parsed = LsToolInputSchema.safeParse(rawArgs); + if (parsed.success) { + return { kind: "ls", toolName, args: parsed.data }; + } + return { kind: "unknown", toolName, args: rawArgs ?? null }; + } + + return { kind: "unknown", toolName, args: rawArgs ?? null }; +} + +function mapFindToolDetail(args: FindToolInput, result: PiToolResult): ToolCallDetail { + return { + type: "search", + query: args.pattern, + toolName: "search", + content: typeof result === "string" ? result : undefined, + }; +} + +function mapGrepToolDetail(args: GrepToolInput, result: PiToolResult): ToolCallDetail { + return { + type: "search", + query: args.pattern, + toolName: "grep", + content: typeof result === "string" ? result : undefined, + }; +} + +function mapLsToolDetail(args: LsToolInput, result: PiToolResult): ToolCallDetail { + const query = args.path ?? "ls"; + return { + type: "search", + query, + content: typeof result === "string" ? result : undefined, + }; +} + +function mapToolDetail(toolCall: PiTrackedToolCall, result?: PiToolResult): ToolCallDetail { + const parsedResult = result ?? null; + + switch (toolCall.kind) { + case "bash": { + const summary = resolveToolCallOutput(parsedResult); + return { + type: "shell", + command: toolCall.args.command, + output: summary.output, + exitCode: summary.exitCode, + }; + } + case "read": + return { + type: "read", + filePath: toolCall.args.path, + content: extractTextFromToolResult(parsedResult), + offset: toolCall.args.offset, + limit: toolCall.args.limit, + }; + case "edit": { + const firstEdit = toolCall.args.edits[0]; + const unifiedDiff = + parsedResult && typeof parsedResult !== "string" ? parsedResult.details?.diff : undefined; + + return { + type: "edit", + filePath: toolCall.args.path, + oldString: firstEdit?.oldText, + newString: firstEdit?.newText, + unifiedDiff, + }; + } + case "write": + return { + type: "write", + filePath: toolCall.args.path, + content: toolCall.args.content, + }; + case "find": + return mapFindToolDetail(toolCall.args, parsedResult); + case "grep": + return mapGrepToolDetail(toolCall.args, parsedResult); + case "ls": + return mapLsToolDetail(toolCall.args, parsedResult); + default: + return { + type: "unknown", + input: toolCall.args, + output: parsedResult, + }; + } +} + +function stringifyUnknownError(error: unknown): string { + if (error instanceof Error) { + return error.message; + } + return typeof error === "string" ? error : "Unknown Pi error"; +} + +function parseModelReference(modelId: string | null): PiModelReference | null { + if (!modelId) { + return null; + } + if (modelId.includes("/")) { + const [provider, ...rest] = modelId.split("/"); + const id = rest.join("/"); + if (provider && id) { + return { provider, id }; + } + } + if (modelId.includes(":")) { + const [provider, ...rest] = modelId.split(":"); + const id = rest.join(":"); + if (provider && id) { + return { provider, id }; + } + } + return { id: modelId }; +} + +function mapResolvedCommand(command: ResolvedCommand): AgentSlashCommand { + return { + name: command.invocationName, + description: command.description ?? "Extension command", + argumentHint: "", + }; +} + +function mapSkillCommand(skill: Skill): AgentSlashCommand { + return { + name: `skill:${skill.name}`, + description: skill.description || "Skill", + argumentHint: "", + }; +} + +function buildSlashCommands(session: PiAgentSession): AgentSlashCommand[] { + const commands: AgentSlashCommand[] = []; + const extensionCommands = session.extensionRunner?.getRegisteredCommands() ?? []; + + for (const command of extensionCommands) { + commands.push(mapResolvedCommand(command)); + } + + for (const template of session.promptTemplates) { + commands.push({ + name: template.name, + description: template.description ?? "Prompt template", + argumentHint: "", + }); + } + + const resourceLoader: ResourceLoader = session.resourceLoader; + const skills = resourceLoader.getSkills().skills; + for (const skill of skills) { + commands.push(mapSkillCommand(skill)); + } + + return commands; +} + +function applySystemPrompt(session: PiAgentSession, systemPrompt: string | undefined): void { + const trimmed = systemPrompt?.trim(); + if (!trimmed) { + return; + } + + // Pi does not expose a public setter for composing an additional system prompt, + // so this escape hatch is isolated to one typed boundary. + const sessionObject = session as object; + const baseSystemPrompt = Reflect.get(sessionObject, "_baseSystemPrompt"); + const currentBase = + typeof baseSystemPrompt === "string" ? baseSystemPrompt : session.agent.state.systemPrompt; + const combinedPrompt = currentBase ? `${currentBase}\n\n${trimmed}` : trimmed; + Reflect.set(sessionObject, "_baseSystemPrompt", combinedPrompt); + session.agent.state.systemPrompt = combinedPrompt; +} + +function isTextContentBlock(block: unknown): block is TextContent { + return PiPromptTextBlockSchema.safeParse(block).success; +} + +function getUserMessageText(content: string | (TextContent | ImageContent)[]): string { + if (typeof content === "string") { + return content; + } + + const textParts: string[] = []; + for (const block of content) { + if (isTextContentBlock(block)) { + textParts.push(block.text); + } + } + return textParts.join("\n\n"); +} + +function getAssistantContentText(content: TextContent | ThinkingContent | ToolCall): string | null { + if (content.type === "text") { + return content.text || null; + } + if (content.type === "thinking") { + return content.thinking || null; + } + return null; +} + +function parsePersistenceMetadata(metadata: AgentMetadata | undefined): PiPersistenceMetadata { + const parsed = PiPersistenceMetadataSchema.safeParse(metadata); + if (parsed.success) { + return parsed.data; + } + return {}; +} + +function getStreamEventTurnId(event: AgentStreamEvent): string | undefined { + switch (event.type) { + case "turn_started": + case "turn_completed": + case "turn_failed": + case "turn_canceled": + case "timeline": + case "permission_requested": + case "permission_resolved": + return event.turnId; + default: + return undefined; + } +} + +function resolveThinkingOptionId( + cachedThinkingOptionId: string | null, + sessionThinkingLevel: ThinkingLevel, +): ThinkingLevel | null { + const currentThinking = cachedThinkingOptionId ?? sessionThinkingLevel; + return normalizePiThinkingOption(currentThinking); +} + +function mapThinkingOption(option: (typeof PI_THINKING_OPTIONS)[number]) { + const mappedOption = { + id: option.id, + label: option.label, + description: option.description, + }; + if (option.isDefault) { + return { + ...mappedOption, + isDefault: true, + }; + } + return mappedOption; +} + +function findModelInRegistry( + registry: ModelRegistry, + parsedReference: PiModelReference, +): Model | undefined { + if (parsedReference.provider) { + return registry.find(parsedReference.provider, parsedReference.id); + } + + return registry.getAll().find((entry) => { + if (entry.id === parsedReference.id) { + return true; + } + return `${entry.provider}/${entry.id}` === parsedReference.id; + }); +} + +export class PiDirectAgentSession implements AgentSession { + readonly provider = PI_PROVIDER; + readonly capabilities = PI_CAPABILITIES; + + private readonly subscribers = new Set<(event: AgentStreamEvent) => void>(); + private readonly activeToolCalls = new Map(); + private activeTurnId: string | null = null; + private lastKnownThinkingOptionId: string | null; + private latestUsage: AgentUsage | undefined; + + constructor( + private readonly session: PiAgentSession, + private readonly modelRegistry: ModelRegistry, + private readonly config: AgentSessionConfig, + ) { + this.lastKnownThinkingOptionId = + normalizePiThinkingOption(config.thinkingOptionId) ?? session.thinkingLevel ?? null; + + this.session.subscribe((event) => { + this.handleSessionEvent(event); + }); + } + + get id(): string | null { + return this.session.sessionId; + } + + private emit(event: AgentStreamEvent): void { + for (const subscriber of this.subscribers) { + subscriber(event); + } + } + + private currentTurnIdForEvent(): string | undefined { + return this.activeTurnId ?? undefined; + } + + private emitToolCallEvent( + toolCallId: string, + toolCall: PiTrackedToolCall, + status: "running" | "completed" | "failed", + result: PiToolResult, + error: unknown, + ): void { + const turnId = this.currentTurnIdForEvent(); + this.emit({ + type: "timeline", + provider: PI_PROVIDER, + turnId, + item: + status === "running" + ? { + type: "tool_call", + callId: toolCallId, + name: toolCall.toolName, + status, + detail: mapToolDetail(toolCall, result), + error: null, + } + : status === "completed" + ? { + type: "tool_call", + callId: toolCallId, + name: toolCall.toolName, + status, + detail: mapToolDetail(toolCall, result), + error: null, + } + : { + type: "tool_call", + callId: toolCallId, + name: toolCall.toolName, + status, + detail: mapToolDetail(toolCall, result), + error, + }, + }); + } + + private handleSessionEvent(event: AgentSessionEvent): void { + const turnId = this.currentTurnIdForEvent(); + + switch (event.type) { + case "agent_start": + this.emit({ + type: "thread_started", + provider: PI_PROVIDER, + sessionId: this.session.sessionId, + }); + return; + case "turn_start": + this.emit({ + type: "turn_started", + provider: PI_PROVIDER, + turnId, + }); + return; + case "message_update": + if (event.message.role !== "assistant") { + return; + } + if (event.assistantMessageEvent.type === "text_delta") { + this.emit({ + type: "timeline", + provider: PI_PROVIDER, + turnId, + item: { + type: "assistant_message", + text: event.assistantMessageEvent.delta ?? "", + }, + }); + return; + } + if (event.assistantMessageEvent.type === "thinking_delta") { + this.emit({ + type: "timeline", + provider: PI_PROVIDER, + turnId, + item: { + type: "reasoning", + text: event.assistantMessageEvent.delta ?? "", + }, + }); + } + return; + case "tool_execution_start": { + const toolCall = parseToolArgs(event.toolName, event.args); + this.activeToolCalls.set(event.toolCallId, toolCall); + this.emitToolCallEvent(event.toolCallId, toolCall, "running", null, null); + return; + } + case "tool_execution_update": { + const toolCall = this.activeToolCalls.get(event.toolCallId); + if (!toolCall) { + return; + } + + const partialResult = parseToolResult(event.partialResult); + this.emitToolCallEvent(event.toolCallId, toolCall, "running", partialResult, null); + return; + } + case "tool_execution_end": { + const toolCall = + this.activeToolCalls.get(event.toolCallId) ?? parseToolArgs(event.toolName, null); + this.activeToolCalls.delete(event.toolCallId); + + const result = parseToolResult(event.result); + const error = event.isError ? event.result : null; + const status = event.isError ? "failed" : "completed"; + this.emitToolCallEvent(event.toolCallId, toolCall, status, result, error); + return; + } + case "turn_end": + return; + case "compaction_start": + this.emit({ + type: "timeline", + provider: PI_PROVIDER, + turnId, + item: { + type: "compaction", + status: "loading", + trigger: event.reason === "manual" ? "manual" : "auto", + }, + }); + return; + case "compaction_end": + this.emit({ + type: "timeline", + provider: PI_PROVIDER, + turnId, + item: { + type: "compaction", + status: "completed", + }, + }); + return; + case "agent_end": { + this.latestUsage = toAgentUsage(this.session.getSessionStats()); + const currentTurnId = turnId; + this.activeTurnId = null; + if (this.session.agent.state.errorMessage) { + this.emit({ + type: "turn_failed", + provider: PI_PROVIDER, + turnId: currentTurnId, + error: this.session.agent.state.errorMessage, + }); + return; + } + this.emit({ + type: "turn_completed", + provider: PI_PROVIDER, + turnId: currentTurnId, + usage: this.latestUsage, + }); + return; + } + default: + return; + } + } + + async run(prompt: AgentPromptInput, options?: AgentRunOptions): Promise { + const timeline: AgentTimelineItem[] = []; + let finalText = ""; + let usage: AgentUsage | undefined; + let turnId: string | null = null; + const bufferedEvents: AgentStreamEvent[] = []; + let settled = false; + let resolveCompletion!: () => void; + let rejectCompletion!: (error: Error) => void; + + function processEvent(event: AgentStreamEvent): void { + if (settled) { + return; + } + + const eventTurnId = getStreamEventTurnId(event); + if (turnId && eventTurnId && eventTurnId !== turnId) { + return; + } + if (event.type === "timeline") { + timeline.push(event.item); + if (event.item.type === "assistant_message") { + finalText += event.item.text; + } + return; + } + if (event.type === "turn_completed") { + usage = event.usage; + settled = true; + resolveCompletion(); + return; + } + if (event.type === "turn_failed") { + settled = true; + rejectCompletion(new Error(event.error)); + } + } + + const completion = new Promise((resolve, reject) => { + resolveCompletion = resolve; + rejectCompletion = reject; + }); + const unsubscribe = this.subscribe((event) => { + if (!turnId) { + bufferedEvents.push(event); + return; + } + processEvent(event); + }); + + try { + const result = await this.startTurn(prompt, options); + turnId = result.turnId; + for (const event of bufferedEvents) { + processEvent(event); + } + if (!settled) { + await completion; + } + } finally { + unsubscribe(); + } + + return { + sessionId: this.session.sessionId, + finalText, + usage, + timeline, + }; + } + + async startTurn(prompt: AgentPromptInput, _options?: AgentRunOptions): Promise { + if (this.activeTurnId) { + throw new Error("A Pi turn is already active"); + } + + const payload = convertPromptInput(prompt); + const turnId = randomUUID(); + this.activeTurnId = turnId; + + void this.session + .prompt(payload.text, payload.images ? { images: payload.images } : undefined) + .catch((error) => { + const failedTurnId = this.activeTurnId ?? turnId; + this.activeTurnId = null; + this.emit({ + type: "turn_failed", + provider: PI_PROVIDER, + turnId: failedTurnId, + error: stringifyUnknownError(error), + }); + }); + + return { turnId }; + } + + subscribe(callback: (event: AgentStreamEvent) => void): () => void { + this.subscribers.add(callback); + return () => { + this.subscribers.delete(callback); + }; + } + + async *streamHistory(): AsyncGenerator { + for (const message of this.session.messages) { + if (message.role === "user") { + const text = getUserMessageText(message.content); + if (text) { + yield { + type: "timeline", + provider: PI_PROVIDER, + item: { type: "user_message", text }, + }; + } + continue; + } + + if (message.role !== "assistant") { + continue; + } + + for (const content of message.content) { + const text = getAssistantContentText(content); + if (!text) { + continue; + } + + if (content.type === "text") { + yield { + type: "timeline", + provider: PI_PROVIDER, + item: { type: "assistant_message", text }, + }; + continue; + } + + if (content.type === "thinking") { + yield { + type: "timeline", + provider: PI_PROVIDER, + item: { type: "reasoning", text }, + }; + } + } + } + } + + async getRuntimeInfo(): Promise { + const thinkingOptionId = resolveThinkingOptionId( + this.lastKnownThinkingOptionId, + this.session.thinkingLevel, + ); + + return { + provider: PI_PROVIDER, + sessionId: this.session.sessionId, + model: this.session.model ? `${this.session.model.provider}/${this.session.model.id}` : null, + thinkingOptionId, + modeId: null, + }; + } + + async getAvailableModes(): Promise { + return []; + } + + async getCurrentMode(): Promise { + return null; + } + + async setMode(modeId: string): Promise { + void modeId; + throw new Error("Pi does not expose selectable modes"); + } + + getPendingPermissions(): AgentPermissionRequest[] { + return []; + } + + async respondToPermission(requestId: string, response: AgentPermissionResponse): Promise { + void requestId; + void response; + } + + describePersistence(): AgentPersistenceHandle | null { + return { + provider: PI_PROVIDER, + sessionId: this.session.sessionId, + nativeHandle: this.session.sessionManager.getSessionFile(), + metadata: { + cwd: this.session.sessionManager.getCwd(), + }, + }; + } + + async interrupt(): Promise { + await this.session.abort(); + } + + async close(): Promise { + this.session.dispose(); + } + + async listCommands(): Promise { + return buildSlashCommands(this.session); + } + + async setModel(modelId: string | null): Promise { + const parsedReference = parseModelReference(modelId); + if (!parsedReference) { + return; + } + + const model = findModelInRegistry(this.modelRegistry, parsedReference); + if (!model) { + throw new Error(`Unknown Pi model: ${modelId}`); + } + + await this.session.setModel(model); + this.config.model = `${model.provider}/${model.id}`; + } + + async setThinkingOption(thinkingOptionId: string | null): Promise { + const thinkingLevel = normalizePiThinkingOption(thinkingOptionId) ?? DEFAULT_PI_THINKING_LEVEL; + this.session.setThinkingLevel(thinkingLevel); + this.lastKnownThinkingOptionId = thinkingLevel; + this.config.thinkingOptionId = thinkingLevel; + } +} + +export class PiDirectAgentClient implements AgentClient { + readonly provider = PI_PROVIDER; + readonly capabilities = PI_CAPABILITIES; + + private readonly logger: Logger; + private readonly runtimeSettings?: ProviderRuntimeSettings; + private modelRegistry: ModelRegistry | null = null; + + constructor(options: PiDirectAgentClientOptions) { + this.logger = options.logger; + this.runtimeSettings = options.runtimeSettings; + } + + private getModelRegistry(): ModelRegistry { + if (!this.modelRegistry) { + this.modelRegistry = ModelRegistry.create(AuthStorage.create()); + } + return this.modelRegistry; + } + + private resolveConfiguredModel(modelId: string | null | undefined): Model | undefined { + const parsedReference = parseModelReference(modelId ?? null); + if (!parsedReference) { + return undefined; + } + + const registry = this.getModelRegistry(); + return findModelInRegistry(registry, parsedReference); + } + + private async createSdkSession(config: AgentSessionConfig): Promise { + const thinkingLevel = + normalizePiThinkingOption(config.thinkingOptionId) ?? DEFAULT_PI_THINKING_LEVEL; + const modelRegistry = this.getModelRegistry(); + const model = this.resolveConfiguredModel(config.model); + + const sessionOptions = { + cwd: config.cwd, + modelRegistry, + sessionManager: SessionManager.create(config.cwd), + thinkingLevel, + ...(model ? { model } : {}), + }; + const { session } = await createAgentSession(sessionOptions); + await session.bindExtensions({}); + applySystemPrompt(session, config.systemPrompt); + return session; + } + + async createSession( + config: AgentSessionConfig, + _launchContext?: AgentLaunchContext, + ): Promise { + const session = await this.createSdkSession(config); + return new PiDirectAgentSession(session, this.getModelRegistry(), config); + } + + async resumeSession( + handle: AgentPersistenceHandle, + overrides?: Partial, + _launchContext?: AgentLaunchContext, + ): Promise { + const sessionFile = handle.nativeHandle; + if (!sessionFile) { + throw new Error("Pi resume requires a native session file handle"); + } + + const resumedManager = SessionManager.open(sessionFile); + const persistenceMetadata = parsePersistenceMetadata(handle.metadata); + const cwd = overrides?.cwd ?? persistenceMetadata.cwd ?? resumedManager.getCwd(); + const mergedConfig: AgentSessionConfig = { + provider: PI_PROVIDER, + cwd, + model: overrides?.model, + thinkingOptionId: overrides?.thinkingOptionId, + systemPrompt: overrides?.systemPrompt, + featureValues: overrides?.featureValues, + title: overrides?.title, + approvalPolicy: overrides?.approvalPolicy, + sandboxMode: overrides?.sandboxMode, + networkAccess: overrides?.networkAccess, + webSearch: overrides?.webSearch, + extra: overrides?.extra, + mcpServers: overrides?.mcpServers, + internal: overrides?.internal, + modeId: overrides?.modeId, + }; + + const model = this.resolveConfiguredModel(mergedConfig.model); + const thinkingLevel = normalizePiThinkingOption(mergedConfig.thinkingOptionId); + const sessionOptions = { + cwd: mergedConfig.cwd, + modelRegistry: this.getModelRegistry(), + sessionManager: resumedManager, + ...(model ? { model } : {}), + ...(thinkingLevel ? { thinkingLevel } : {}), + }; + const { session } = await createAgentSession(sessionOptions); + await session.bindExtensions({}); + applySystemPrompt(session, mergedConfig.systemPrompt); + return new PiDirectAgentSession(session, this.getModelRegistry(), mergedConfig); + } + + async listModels(_options?: ListModelsOptions): Promise { + const models = this.getModelRegistry() + .getAll() + .map((model) => ({ + provider: PI_PROVIDER, + id: `${model.provider}/${model.id}`, + label: `${model.provider}/${model.name}`, + description: `${model.provider}/${model.id}`, + metadata: { + provider: model.provider, + modelId: model.id, + } satisfies AgentMetadata, + thinkingOptions: model.reasoning ? PI_THINKING_OPTIONS.map(mapThinkingOption) : undefined, + defaultThinkingOptionId: model.reasoning ? DEFAULT_PI_THINKING_LEVEL : undefined, + })); + + return transformPiModels(models); + } + + async listModes(): Promise { + return []; + } + + async isAvailable(): Promise { + const command = this.runtimeSettings?.command; + if (command?.mode === "replace" && command.argv[0]) { + if (!existsSync(command.argv[0])) { + return false; + } + } else if (!(await isCommandAvailable(PI_BINARY_COMMAND))) { + return false; + } + + return ( + Boolean(process.env.OPENAI_API_KEY) || + Boolean(process.env.ANTHROPIC_API_KEY) || + Boolean(process.env.OPENROUTER_API_KEY) || + existsSync(join(homedir(), ".pi", "agent", "auth.json")) + ); + } + + async getDiagnostic(): Promise<{ diagnostic: string }> { + try { + const available = await this.isAvailable(); + const binaryOverride = this.runtimeSettings?.command; + const binary = + binaryOverride?.mode === "replace" && binaryOverride.argv[0] + ? binaryOverride.argv[0] + : await findExecutable(PI_BINARY_COMMAND); + const version = binary ? await resolveBinaryVersion(binary) : "unknown"; + const authConfigPath = join(homedir(), ".pi", "agent", "auth.json"); + let modelsValue = "Not checked"; + let status = formatDiagnosticStatus(available); + + if (available) { + try { + const models = await this.listModels(); + modelsValue = String(models.length); + } catch (error) { + modelsValue = `Error - ${toDiagnosticErrorMessage(error)}`; + status = formatDiagnosticStatus(available, { + source: "model fetch", + cause: error, + }); + } + } + + return { + diagnostic: formatProviderDiagnostic("Pi", [ + { label: "Binary", value: binary ?? "not found" }, + { label: "Version", value: version }, + { + label: "OPENAI_API_KEY", + value: process.env.OPENAI_API_KEY ? "set" : "not set", + }, + { + label: "ANTHROPIC_API_KEY", + value: process.env.ANTHROPIC_API_KEY ? "set" : "not set", + }, + { + label: "OPENROUTER_API_KEY", + value: process.env.OPENROUTER_API_KEY ? "set" : "not set", + }, + { + label: "Auth config (~/.pi/agent/auth.json)", + value: existsSync(authConfigPath) ? "found" : "not found", + }, + { label: "Models", value: modelsValue }, + { label: "Status", value: status }, + ]), + }; + } catch (error) { + this.logger.debug({ err: error }, "Pi diagnostic lookup failed"); + return { + diagnostic: formatProviderDiagnosticError("Pi", error), + }; + } + } +} diff --git a/packages/server/src/server/daemon-e2e/agent-configs.ts b/packages/server/src/server/daemon-e2e/agent-configs.ts index a8e1d0245..ead0551cb 100644 --- a/packages/server/src/server/daemon-e2e/agent-configs.ts +++ b/packages/server/src/server/daemon-e2e/agent-configs.ts @@ -126,7 +126,9 @@ export function isProviderAvailable(provider: AgentProvider): Promise { return await isCommandAvailable("opencode"); case "pi": return ( - (await isCommandAvailable(process.env.PI_ACP_PI_COMMAND ?? "pi")) && + (await isCommandAvailable( + process.env.PI_COMMAND ?? process.env.PI_ACP_PI_COMMAND ?? "pi", + )) && (Boolean(process.env.OPENAI_API_KEY) || Boolean(process.env.ANTHROPIC_API_KEY) || Boolean(process.env.OPENROUTER_API_KEY) || diff --git a/packages/server/src/server/daemon-e2e/pi.real.e2e.test.ts b/packages/server/src/server/daemon-e2e/pi.real.e2e.test.ts index 236a7c0c0..63a5cac7c 100644 --- a/packages/server/src/server/daemon-e2e/pi.real.e2e.test.ts +++ b/packages/server/src/server/daemon-e2e/pi.real.e2e.test.ts @@ -1,84 +1,436 @@ -import { beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { mkdtempSync, rmSync } from "node:fs"; +import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; +import { randomUUID } from "node:crypto"; +import { beforeAll, beforeEach, describe, expect, test } from "vitest"; import pino from "pino"; -import { PiACPAgentClient } from "../agent/providers/pi-acp-agent.js"; +import type { AgentPersistenceHandle, AgentTimelineItem } from "../agent/agent-sdk-types.js"; +import { PiDirectAgentClient } from "../agent/providers/pi-direct-agent.js"; import { DaemonClient } from "../test-utils/daemon-client.js"; import { createTestPaseoDaemon } from "../test-utils/paseo-daemon.js"; import { isProviderAvailable } from "./agent-configs.js"; process.env.PASEO_SUPERVISED = "0"; -function tmpCwd(): string { - return mkdtempSync(path.join(tmpdir(), "daemon-real-pi-")); +const PI_TEST_TIMEOUT_MS = 240_000; +const PI_SUITE_TIMEOUT_MS = 600_000; +const PI_REAL_TEST_MODEL = "openrouter/google/gemini-2.5-flash-lite"; + +type ToolCallItem = Extract; + +function tmpCwd(prefix = "daemon-real-pi-"): string { + return mkdtempSync(path.join(tmpdir(), prefix)); } -describe("daemon E2E (real pi)", () => { - let canRun = false; +function createPiClient(): PiDirectAgentClient { + return new PiDirectAgentClient({ logger: pino({ level: "silent" }) }); +} - beforeAll(async () => { - canRun = await isProviderAvailable("pi"); +function createPiToolDaemon() { + const logger = pino({ level: "silent" }); + return createTestPaseoDaemon({ + agentClients: { pi: new PiDirectAgentClient({ logger }) }, + logger, }); +} - beforeEach((context) => { - if (!canRun) { - context.skip(); - } +function extractAssistantText(items: AgentTimelineItem[]): string { + return items + .filter( + (item): item is Extract => + item.type === "assistant_message", + ) + .map((item) => item.text) + .join("\n"); +} + +function extractCompletedToolCalls(items: AgentTimelineItem[]): ToolCallItem[] { + return items.filter( + (item): item is ToolCallItem => item.type === "tool_call" && item.status === "completed", + ); +} + +function findCompletedToolCall( + items: AgentTimelineItem[], + predicate: (item: ToolCallItem) => boolean, +): ToolCallItem | undefined { + return extractCompletedToolCalls(items).find(predicate); +} + +async function fetchCanonicalTimeline( + client: DaemonClient, + agentId: string, +): Promise { + const timeline = await client.fetchAgentTimeline(agentId, { + direction: "tail", + limit: 0, + projection: "canonical", }); + return timeline.entries.map((entry) => entry.item); +} - test("smoke test with thinking option configured separately from modes", async () => { - const logger = pino({ level: "silent" }); - const cwd = tmpCwd(); - const daemon = await createTestPaseoDaemon({ - agentClients: { pi: new PiACPAgentClient({ logger }) }, - logger, +async function withConnectedPiDaemon( + run: (context: { client: DaemonClient }) => Promise, +): Promise { + const daemon = await createPiToolDaemon(); + const client = new DaemonClient({ url: `ws://127.0.0.1:${daemon.port}/ws` }); + + try { + await client.connect(); + await client.fetchAgents({ + subscribe: { subscriptionId: `pi-real-${randomUUID()}` }, }); - const client = new DaemonClient({ url: `ws://127.0.0.1:${daemon.port}/ws` }); + await run({ client }); + } finally { + await client.close().catch(() => undefined); + await daemon.close().catch(() => undefined); + } +} - try { - await client.connect(); - await client.fetchAgents({ - subscribe: { subscriptionId: "pi-real-smoke" }, - }); +describe( + "daemon E2E (real pi)", + () => { + let canRun = false; - const agent = await client.createAgent({ - cwd, - title: "pi-real-smoke", - provider: "pi", - thinkingOptionId: "medium", - }); + beforeAll(async () => { + canRun = await isProviderAvailable("pi"); + }); - await client.sendMessage(agent.id, "Reply with exactly: PINEAPPLE"); + beforeEach((context) => { + if (!canRun) { + context.skip(); + } + }); - const finish = await client.waitForFinish(agent.id, 240_000); - expect(finish.status).toBe("idle"); - expect(finish.final?.persistence).toBeTruthy(); - expect(finish.final?.persistence?.provider).toBe("pi"); - expect(finish.final?.persistence?.sessionId).toBeTruthy(); + test( + "bash tool call records completed shell detail and output", + async () => { + const cwd = tmpCwd(); - const timeline = await client.fetchAgentTimeline(agent.id, { - direction: "tail", - limit: 0, - projection: "canonical", - }); - const assistantText = timeline.entries - .filter( - ( - entry, - ): entry is typeof entry & { - item: { type: "assistant_message"; text: string }; - } => entry.item.type === "assistant_message", - ) - .map((entry) => entry.item.text) - .join("\n"); + try { + await withConnectedPiDaemon(async ({ client }) => { + const agent = await client.createAgent({ + cwd, + title: "pi-bash-tool-call", + provider: "pi", + model: PI_REAL_TEST_MODEL, + }); - expect(assistantText.replace(/\s+/g, "")).toContain("PINEAPPLE"); - } finally { - await client.close().catch(() => undefined); - await daemon.close().catch(() => undefined); - rmSync(cwd, { recursive: true, force: true }); - } - }, 420_000); -}); + await client.sendMessage( + agent.id, + "Use the bash tool and run this exact bash command: echo HELLO_PI_TEST", + ); + + const finish = await client.waitForFinish(agent.id, PI_TEST_TIMEOUT_MS); + expect(finish.status).toBe("idle"); + + const items = await fetchCanonicalTimeline(client, agent.id); + const toolCall = findCompletedToolCall( + items, + (item) => + item.detail.type === "shell" && item.detail.command.includes("echo HELLO_PI_TEST"), + ); + + expect(toolCall).toBeDefined(); + expect(toolCall?.status).toBe("completed"); + expect(toolCall?.detail.type).toBe("shell"); + if (toolCall?.detail.type === "shell") { + expect(toolCall.detail.command).toContain("echo HELLO_PI_TEST"); + expect(toolCall.detail.output).toContain("HELLO_PI_TEST"); + } + }); + } finally { + rmSync(cwd, { recursive: true, force: true }); + } + }, + PI_TEST_TIMEOUT_MS, + ); + + test( + "file read tool call captures read detail and content", + async () => { + const cwd = tmpCwd(); + const filename = "pi-read.txt"; + const expectedContent = "PI_READ_CONTENT_12345"; + + try { + writeFileSync(path.join(cwd, filename), expectedContent, "utf8"); + + await withConnectedPiDaemon(async ({ client }) => { + const agent = await client.createAgent({ + cwd, + title: "pi-file-read", + provider: "pi", + model: PI_REAL_TEST_MODEL, + }); + + await client.sendMessage( + agent.id, + `Use the read tool to read the file ${filename} and tell me its contents exactly.`, + ); + + const finish = await client.waitForFinish(agent.id, PI_TEST_TIMEOUT_MS); + expect(finish.status).toBe("idle"); + + const items = await fetchCanonicalTimeline(client, agent.id); + const toolCall = findCompletedToolCall( + items, + (item) => + item.detail.type === "read" && + item.detail.filePath.includes(filename) && + item.detail.content?.includes(expectedContent) === true, + ); + + expect(toolCall).toBeDefined(); + expect(toolCall?.detail.type).toBe("read"); + if (toolCall?.detail.type === "read") { + expect(toolCall.detail.filePath).toContain(filename); + expect(toolCall.detail.content).toContain(expectedContent); + } + }); + } finally { + rmSync(cwd, { recursive: true, force: true }); + } + }, + PI_TEST_TIMEOUT_MS, + ); + + test( + "file write tool call captures write detail and writes to disk", + async () => { + const cwd = tmpCwd(); + const filename = "pi-test-write.txt"; + const expectedContent = "PI_WRITE_CONTENT_67890"; + + try { + await withConnectedPiDaemon(async ({ client }) => { + const agent = await client.createAgent({ + cwd, + title: "pi-file-write", + provider: "pi", + model: PI_REAL_TEST_MODEL, + }); + + await client.sendMessage( + agent.id, + `Use the write tool to write a file called ${filename} in the current directory with the exact content ${expectedContent}`, + ); + + const finish = await client.waitForFinish(agent.id, PI_TEST_TIMEOUT_MS); + expect(finish.status).toBe("idle"); + + const items = await fetchCanonicalTimeline(client, agent.id); + const toolCall = findCompletedToolCall( + items, + (item) => item.detail.type === "write" && item.detail.filePath.includes(filename), + ); + + expect(toolCall).toBeDefined(); + expect(toolCall?.detail.type).toBe("write"); + expect(existsSync(path.join(cwd, filename))).toBe(true); + expect(readFileSync(path.join(cwd, filename), "utf8")).toBe(expectedContent); + }); + } finally { + rmSync(cwd, { recursive: true, force: true }); + } + }, + PI_TEST_TIMEOUT_MS, + ); + + test( + "file edit tool call captures edit detail and updates the file on disk", + async () => { + const cwd = tmpCwd(); + const filename = "pi-edit.txt"; + const filePath = path.join(cwd, filename); + + try { + writeFileSync(filePath, "BEFORE_EDIT", "utf8"); + + await withConnectedPiDaemon(async ({ client }) => { + const agent = await client.createAgent({ + cwd, + title: "pi-file-edit", + provider: "pi", + model: PI_REAL_TEST_MODEL, + }); + + await client.sendMessage( + agent.id, + `Use the edit tool on the file ${filename} and replace BEFORE_EDIT with AFTER_EDIT. Do not just describe the change.`, + ); + + const finish = await client.waitForFinish(agent.id, PI_TEST_TIMEOUT_MS); + expect(finish.status).toBe("idle"); + + const items = await fetchCanonicalTimeline(client, agent.id); + const toolCall = findCompletedToolCall( + items, + (item) => item.detail.type === "edit" && item.detail.filePath.includes(filename), + ); + + expect(toolCall).toBeDefined(); + expect(toolCall?.detail.type).toBe("edit"); + expect(readFileSync(filePath, "utf8")).toContain("AFTER_EDIT"); + }); + } finally { + rmSync(cwd, { recursive: true, force: true }); + } + }, + PI_TEST_TIMEOUT_MS, + ); + + test( + "thinking-enabled runs emit reasoning timeline chunks", + async () => { + const cwd = tmpCwd(); + + try { + await withConnectedPiDaemon(async ({ client }) => { + const agent = await client.createAgent({ + cwd, + title: "pi-reasoning", + provider: "pi", + model: PI_REAL_TEST_MODEL, + thinkingOptionId: "high", + }); + + await client.sendMessage( + agent.id, + "Think step by step about what 7 * 13 equals, and give the final answer at the end.", + ); + + const finish = await client.waitForFinish(agent.id, PI_TEST_TIMEOUT_MS); + expect(finish.status).toBe("idle"); + + const items = await fetchCanonicalTimeline(client, agent.id); + const reasoningItems = items.filter( + (item): item is Extract => + item.type === "reasoning" && item.text.trim().length > 0, + ); + + expect(reasoningItems.length).toBeGreaterThan(0); + }); + } finally { + rmSync(cwd, { recursive: true, force: true }); + } + }, + PI_TEST_TIMEOUT_MS, + ); + + test( + "session persistence survives delete and resume", + async () => { + const cwd = tmpCwd(); + const rememberedToken = "PERSISTENCE_TOKEN_42"; + + try { + await withConnectedPiDaemon(async ({ client }) => { + const agent = await client.createAgent({ + cwd, + title: "pi-persistence", + provider: "pi", + model: PI_REAL_TEST_MODEL, + }); + + await client.sendMessage(agent.id, `Remember this code: ${rememberedToken}`); + + const initialFinish = await client.waitForFinish(agent.id, PI_TEST_TIMEOUT_MS); + expect(initialFinish.status).toBe("idle"); + expect(initialFinish.final?.persistence).toBeTruthy(); + + const handle = initialFinish.final?.persistence as AgentPersistenceHandle; + await client.deleteAgent(agent.id); + + const resumed = await client.resumeAgent(handle); + await client.sendMessage(resumed.id, "What was the code I asked you to remember?"); + + const resumedFinish = await client.waitForFinish(resumed.id, PI_TEST_TIMEOUT_MS); + expect(resumedFinish.status).toBe("idle"); + + const items = await fetchCanonicalTimeline(client, resumed.id); + const assistantText = extractAssistantText(items).toUpperCase(); + expect(assistantText.includes(rememberedToken) || assistantText.includes("42")).toBe( + true, + ); + }); + } finally { + rmSync(cwd, { recursive: true, force: true }); + } + }, + PI_TEST_TIMEOUT_MS, + ); + + test( + "PiDirectAgentClient.listModels returns non-empty Pi model definitions", + async () => { + const client = createPiClient(); + const models = await client.listModels(); + + expect(models.length).toBeGreaterThan(0); + for (const model of models) { + expect(model.provider).toBe("pi"); + expect(typeof model.id).toBe("string"); + expect(model.id.length).toBeGreaterThan(0); + expect(typeof model.label).toBe("string"); + expect(model.label.length).toBeGreaterThan(0); + } + }, + PI_TEST_TIMEOUT_MS, + ); + + test( + "session getRuntimeInfo reflects configured high thinking level", + async () => { + const cwd = tmpCwd("pi-runtime-info-"); + const client = createPiClient(); + + try { + const session = await client.createSession({ + provider: "pi", + cwd, + thinkingOptionId: "high", + }); + + try { + const runtimeInfo = await session.getRuntimeInfo(); + expect(runtimeInfo.thinkingOptionId).toBe("high"); + } finally { + await session.close(); + } + } finally { + rmSync(cwd, { recursive: true, force: true }); + } + }, + PI_TEST_TIMEOUT_MS, + ); + + test( + "session setThinkingOption('low') updates runtime thinking level", + async () => { + const cwd = tmpCwd("pi-feature-"); + const client = createPiClient(); + + try { + const session = await client.createSession({ + provider: "pi", + cwd, + }); + + try { + await session.setThinkingOption?.("low"); + const runtimeInfo = await session.getRuntimeInfo(); + expect(runtimeInfo.thinkingOptionId).toBe("low"); + } finally { + await session.close(); + } + } finally { + rmSync(cwd, { recursive: true, force: true }); + } + }, + PI_TEST_TIMEOUT_MS, + ); + }, + PI_SUITE_TIMEOUT_MS, +);