From 94f9798977c4c6a73c9a17c32982cb140a90096c Mon Sep 17 00:00:00 2001 From: Jonathan Borgwing Date: Sun, 19 Jul 2026 13:46:59 -0400 Subject: [PATCH] fix: stabilize Claude bridge on OMP 17 --- README.md | 103 ++------ bun.lock | 202 +++++++++------ claude-bridge.example.json | 3 - ...26-07-19_omp-cloud-bridge-compatibility.md | 73 ++++++ package.json | 34 +-- src/config.ts | 10 - src/index.ts | 141 +++------- src/models.ts | 240 ++---------------- src/provider-registration.ts | 31 +++ tests/unit-context-window.mjs | 119 --------- tests/unit-models.mjs | 56 ++++ tests/unit-provider-registration.mjs | 37 +++ 12 files changed, 421 insertions(+), 628 deletions(-) create mode 100644 documentation/completed/improvements/2026-07-19_omp-cloud-bridge-compatibility.md create mode 100644 src/provider-registration.ts delete mode 100644 tests/unit-context-window.mjs create mode 100644 tests/unit-models.mjs create mode 100644 tests/unit-provider-registration.mjs diff --git a/README.md b/README.md index d7c0f57..9691cdd 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@

omp-claude-bridge

-

Run Claude Code as a first-class model provider inside Oh My Pi — with an AskClaude delegation tool and switchable 1M / 200K context windows.

+

Run Claude Code as a first-class model provider inside Oh My Pi — with native OMP model selection and an AskClaude delegation tool.

License: MIT @@ -19,9 +19,9 @@ --- -`omp-claude-bridge` lets you drive **Claude Code** — Opus, Sonnet, Haiku, and Fable — from inside Oh My Pi, with every tool call flowing through OMP's native TUI. It also exposes an **AskClaude** tool so any other provider can delegate a task or a second opinion to Claude Code, and it gives you **direct control over the context window** each model requests. +`omp-claude-bridge` lets you drive **Claude Code** — Opus, Sonnet, Haiku, and Fable — from inside Oh My Pi, with every tool call flowing through OMP's native TUI. It also exposes an **AskClaude** tool so any other provider can delegate a task or a second opinion to Claude Code. -Authentication and billing run through Claude Code and your Anthropic subscription via the official [Claude Agent SDK](https://github.com/anthropics/claude-agent-sdk-typescript) — this extension never stores credentials. +Authentication is delegated unchanged to the official [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk). The bridge provides no login flow and does not read, store, validate, log, or inject Claude credentials.

  @@ -33,7 +33,8 @@ Authentication and billing run through Claude Code and your Anthropic subscripti - [Features](#features) - [Install](#install) - [Quickstart](#quickstart) -- [Context window controls](#context-window-controls) +- [Authentication and billing](#authentication-and-billing) +- [Context handling](#context-handling) - [Models](#models) - [AskClaude tool](#askclaude-tool) - [Configuration reference](#configuration-reference) @@ -47,7 +48,7 @@ Authentication and billing run through Claude Code and your Anthropic subscripti - **Claude Code as a provider** — pick Opus / Sonnet / Haiku / Fable from `/model`; tool calls render in OMP's TUI like any native provider. - **AskClaude delegation tool** — from any other provider, hand a task or question to Claude Code (read-only, no-tools, or full read/write/bash), optionally in an isolated session. -- **Switchable context window** — force **1M** or **200K** globally, or leave it on measured per-model defaults. This is the headline addition in this fork. +- **Canonical OMP models** — one native picker entry per supported model, with OMP's catalog metadata preserved unchanged. - **Session resume & persistence** — conversations survive across turns and reconnects. - **Skills + AGENTS.md forwarding** — your OMP skills and context files are passed into Claude Code's system prompt. - **Thinking support** — effort levels map through to Claude Code, including `xhigh` on Sonnet models. @@ -73,7 +74,7 @@ omp plugin install ./omp-claude-bridge -Requires Oh My Pi (`omp`) and a working Claude Code login. +Requires Oh My Pi (`omp`) and either an existing local Claude Code login or `ANTHROPIC_API_KEY` in the parent environment. ## Quickstart @@ -83,74 +84,33 @@ Requires Oh My Pi (`omp`) and a working Claude Code login. To delegate from another provider instead, just ask: *"Ask Claude to review this plan and poke holes in it."* -## Context window controls +## Authentication and billing -Claude Code serves different context windows depending on the exact model id it receives (e.g. bare `claude-fable-5` serves 200K, while `claude-fable-5[1m]` serves 1M). `omp-claude-bridge` exposes both as **separate entries in the `/model` picker**, so you choose the window on demand: +The bridge calls the official Claude Agent SDK's `query()` without an `env` override, credential material, auth callback, or login command. Claude Code inherits the parent environment, remains the sole credential resolver, and applies its own authentication precedence. The bridge sets only non-credential runtime controls that suppress nonessential traffic, native Claude Code autocompaction, and Claude.ai cloud MCP auto-discovery. -- `claude-bridge/claude-opus-4-8` → **Opus 4.8 (1M)** -- `claude-bridge/claude-opus-4-8-200k` → **Opus 4.8 (200K)** +- An existing local Claude Code login currently draws from the user's Claude subscription quota. +- `ANTHROPIC_API_KEY` uses Anthropic API billing. -Switching window is just picking the other entry — no config edit, no reload. Every model appears once per window it supports, the `(1M)` / `(200K)` label is always shown, and each entry reports its true window so OMP's status bar and auto-compaction threshold stay accurate. +The bridge has no login flow and does not handle credentials. Anthropic's [June 15 support update](https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan) currently says third-party Agent SDK usage draws from subscription limits. The [Agent SDK overview](https://code.claude.com/docs/en/agent-sdk) also says third-party developers may not offer Claude.ai login or rate limits without prior approval. This repository does not claim explicit Anthropic approval; policy and billing behavior are subject to Anthropic change. -### Default window -The **unsuffixed** id (e.g. `claude-opus-4-8`) maps to a default window; the other window gets a `-1m` / `-200k` suffixed id. `provider.contextWindow` in `~/.omp/agent/claude-bridge.json` picks that default — it no longer hides models, it only decides which window is unsuffixed: +## Context handling -```json -{ - "provider": { - "contextWindow": "auto" - } -} -``` - -| Mode | Default (unsuffixed) window | -| ---- | -------- | -| `"auto"` *(default)* | Per-model measured default. Respects `plan` and `longContextExtraUsage`. | -| `"1m"` | 1M where the model has a 1M runtime, else its only window. | -| `"200k"` | 200K where the model has a 200K runtime, else its only window. | +The bridge registers exactly one canonical OMP catalog entry per supported model and passes that model ID unchanged to Claude Code. It does not create context-window aliases, rewrite model IDs, or advertise account-entitlement variants. -Both windows stay in the picker regardless of this setting (wherever a runtime exists); it only changes which one is the plain, unsuffixed id. So `modelRoles` / `enabledModels` that reference `claude-bridge/claude-opus-4-8` keep working and follow the default. - -### Windows offered per model - -| Model | 200K entry | 1M entry | `auto` default | -| ----- | :--------: | :------: | :------------: | -| `claude-opus-4-8` | ✓ | ✓ | 1M | -| `claude-opus-4-7` | — | ✓ | 1M | -| `claude-opus-4-6` | ✓ | ✓ | 200K¹ | -| `claude-fable-5` | ✓ | ✓ | 200K | -| `claude-sonnet-5` | ✓ | ✓ | 1M | -| `claude-sonnet-4-6` | ✓ | ✓ | 200K² | -| `claude-haiku-4-5` | ✓ | — | 200K | - -¹ Opus 4.6's `auto` default is 1M when `plan: "max"` or `longContextExtraUsage: true`. -² Sonnet 4.6's `auto` default is 1M when `longContextExtraUsage: true`. - -The suffixed alternate exists only for the window that isn't the default — e.g. under `auto` you get `claude-opus-4-8` (1M) + `claude-opus-4-8-200k`, and under `"200k"` you get `claude-opus-4-8` (200K) + `claude-opus-4-8-1m`. - -> Forcing 1M is a *request*: some models may still be **served** 200K by your subscription entitlement. Set `CLAUDE_BRIDGE_DEBUG=1` to log the served window (see [Debugging](#debugging)). - -> An invalid `contextWindow` value logs a warning and falls back to `"auto"`, so a typo never breaks startup. +Use [`omp-ccwindow`](https://github.com/DevVig/omp-ccwindow) when you want to lower OMP's active context value for status display and compaction timing. That plugin changes OMP's local model clone; it does not change the Claude API model's native context capacity. ## Models -Pick any of these from `/model` — each entry shows a `(1M)` or `(200K)` label. The exact ids below assume the default `contextWindow: "auto"`; which id is unsuffixed vs `-1m` / `-200k` follows your configured [default window](#default-window). - -| Picker id (auto) | Window | -| --------- | ------ | -| `claude-bridge/claude-fable-5` | 200K | -| `claude-bridge/claude-fable-5-1m` | 1M | -| `claude-bridge/claude-opus-4-8` | 1M | -| `claude-bridge/claude-opus-4-8-200k` | 200K | -| `claude-bridge/claude-opus-4-7` | 1M | -| `claude-bridge/claude-opus-4-6` | 200K (1M on Max / Extra Usage) | -| `claude-bridge/claude-opus-4-6-1m` | 1M | -| `claude-bridge/claude-sonnet-5` | 1M (supports `xhigh`) | -| `claude-bridge/claude-sonnet-5-200k` | 200K | -| `claude-bridge/claude-sonnet-4-6` | 200K (supports `xhigh`) | -| `claude-bridge/claude-sonnet-4-6-1m` | 1M | -| `claude-bridge/claude-haiku-4-5` | 200K (cheapest) | +The bridge exposes these canonical picker entries: + +- `claude-bridge/claude-fable-5` +- `claude-bridge/claude-opus-4-8` +- `claude-bridge/claude-opus-4-7` +- `claude-bridge/claude-opus-4-6` +- `claude-bridge/claude-sonnet-5` +- `claude-bridge/claude-sonnet-4-6` +- `claude-bridge/claude-haiku-4-5` Bash commands issued by Claude Code get a 120-second default timeout (matching Claude Code's default), since OMP's bash has no timeout by default. @@ -188,9 +148,6 @@ Config is read from `~/.omp/agent/claude-bridge.json` (global) and the project O "defaultIsolated": false }, "provider": { - "contextWindow": "auto", - "plan": "pro", - "longContextExtraUsage": false, "strictMcpConfig": true } } @@ -213,17 +170,14 @@ Config is read from `~/.omp/agent/claude-bridge.json` (global) and the project O | Key | Default | Description | | --- | ------- | ----------- | -| `contextWindow` | `"auto"` | `"auto"`, `"1m"`, or `"200k"`. See [Context window controls](#context-window-controls). | -| `plan` | `"pro"` | Set to `"max"` to enable Opus 4.6 at 1M in `auto`. | -| `longContextExtraUsage` | `false` | Opt into metered 1M usage (enables Sonnet 4.6 1M everywhere, Opus 4.6 1M on Pro). | | `appendSystemPrompt` | `true` | Append OMP's AGENTS.md and skills. | | `settingSources` | — | Claude Code filesystem settings to load; only applied when `appendSystemPrompt: false`. | -| `strictMcpConfig` | `true` | Block MCP servers from `~/.claude.json` / `.mcp.json`. Cloud MCP is always blocked. | +| `strictMcpConfig` | `true` | Ignore filesystem MCP configuration outside the bridge's OMP tool server; Claude.ai cloud MCP auto-discovery is also disabled. | | `pathToClaudeCodeExecutable` | — | Path to the `claude` binary, if the bundled one can't run on your OS/filesystem. | ## How it works -OMP's built-in tools are bridged to Claude Code and back, so from your side it behaves like any other OMP provider. Model routing lives in [`src/models.ts`](src/models.ts), which is deliberately free of runtime imports so the context-window policy stays unit-testable in isolation. On registration, the extension projects the pi-ai model list, applies the selected context-window policy, and registers the resulting models with OMP. +OMP's built-in tools are bridged to Claude Code and back, so from your side it behaves like any other OMP provider. On every extension initialization, the bridge registers the canonical OMP Anthropic catalog entries while retaining the parent session's process-global stream function. Agent SDK queries receive the selected canonical model ID and resolve authentication entirely inside Claude Code. ## Debugging @@ -251,12 +205,11 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for the full workflow. CI runs typecheck - Original **[pi-claude-bridge](https://github.com/elidickinson/pi-claude-bridge)** by **[Eli Dickinson](https://github.com/elidickinson)** — the streaming provider, MCP/tool bridging, session resume, and AskClaude tool this project builds on. - Initial inspiration from [claude-agent-sdk-pi](https://github.com/prateekmedia/claude-agent-sdk-pi) by Prateek Sunal. -- **Oh My Pi port and context-window controls** by **[Jonathan Borgwing](https://github.com/DevVig)**. +- **Oh My Pi port and maintenance** by **[Jonathan Borgwing](https://github.com/DevVig)**. See [NOTICE](NOTICE) for full attribution. -> Anthropic [announced and then unannounced](https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan) a change to how Agent-SDK tool usage is billed. As of June 15, 2026 it uses your subscription quota just like Claude Code direct. ## License -[MIT](LICENSE) © 2026 Eli Dickinson (original) and Jonathan Borgwing (Oh My Pi port and context-window controls). +[MIT](LICENSE) © 2026 Eli Dickinson (original) and Jonathan Borgwing (Oh My Pi port). diff --git a/bun.lock b/bun.lock index 2806c7e..317e513 100644 --- a/bun.lock +++ b/bun.lock @@ -5,28 +5,30 @@ "": { "name": "omp-claude-bridge", "dependencies": { - "@anthropic-ai/claude-agent-sdk": "^0.2.141", - "@anthropic-ai/sdk": "^0.73.0", + "@anthropic-ai/claude-agent-sdk": "^0.3.215", + "@anthropic-ai/sdk": "^0.112.3", + "@modelcontextprotocol/sdk": "^1.29.0", "cc-session-io": "^0.3.1", "change-case": "^5.4.4", "typebox": "^1.3.0", + "zod": "^4.4.3", }, "devDependencies": { - "@oh-my-pi/pi-agent-core": "^16.3.6", - "@oh-my-pi/pi-ai": "^16.3.6", - "@oh-my-pi/pi-coding-agent": "^16.3.6", - "@oh-my-pi/pi-tui": "^16.3.6", - "@oh-my-pi/pi-utils": "^16.3.6", + "@oh-my-pi/pi-agent-core": "^17.0.5", + "@oh-my-pi/pi-ai": "^17.0.5", + "@oh-my-pi/pi-coding-agent": "^17.0.5", + "@oh-my-pi/pi-tui": "^17.0.5", + "@oh-my-pi/pi-utils": "^17.0.5", "@types/node": "^24.13.2", "tsx": "^4.22.4", "typescript": "^6.0.3", }, "peerDependencies": { - "@oh-my-pi/pi-agent-core": ">=16.3.6", - "@oh-my-pi/pi-ai": ">=16.3.6", - "@oh-my-pi/pi-coding-agent": ">=16.3.6", - "@oh-my-pi/pi-tui": ">=16.3.6", - "@oh-my-pi/pi-utils": ">=16.3.6", + "@oh-my-pi/pi-agent-core": ">=17.0.5", + "@oh-my-pi/pi-ai": ">=17.0.5", + "@oh-my-pi/pi-coding-agent": ">=17.0.5", + "@oh-my-pi/pi-tui": ">=17.0.5", + "@oh-my-pi/pi-utils": ">=17.0.5", }, "optionalPeers": [ "@oh-my-pi/pi-agent-core", @@ -41,31 +43,31 @@ "esbuild", ], "packages": { - "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.25.0", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-wU1VgXNtMvdVotX49txc3WJUDV+/QbLpsgjMvFhlRmp37osdLbI7L7y+iwAlQATwfjLxcv1r1p3ZxZBcXlGhcQ=="], + "@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@1.2.1", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-jwYUdOQR7tc+Zfch53VL4JJyUNK/46q03uUTYb+PjECsmnNl94XFXOfYLJ8RBpMNidXd1rpOAVgb0vqD98xImA=="], - "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.141", "", { "dependencies": { "@anthropic-ai/sdk": "^0.93.0", "@modelcontextprotocol/sdk": "^1.29.0" }, "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.2.141", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.2.141", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.2.141", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.2.141", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.2.141", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.2.141", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.2.141", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.2.141" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-AIBacMWGcZIUcXlUoObqjwJ6pmJI3BayAqPAFXuvSq3DHJXdiuZVs7l/zTB5l3nRhRv5cqSrI2XbiDeHgZWizw=="], + "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.215", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.215", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.215", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.215", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.215", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.215", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.215", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.215", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.215" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-fBktJCwfu8ZeOSnnSLcWVkIHyp/pjouJsGVGtRnQ0HkcRuOReIbRcB/6n2O5dYV331Ok+MfdGHiPaTORj7pCtQ=="], - "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.2.141", "", { "os": "darwin", "cpu": "arm64" }, "sha512-9HZ0ot6+FwOfQ1aeMqQLH4IJGMm/DcP08SysDxscVjBm6l2JjqleHohxi3zid0DurfGweqT+4x9GScJffwg55g=="], + "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.215", "", { "os": "darwin", "cpu": "arm64" }, "sha512-KIOe3N/ypVIdsI7fnJUHT0Djei1RH01TbxK6LI2mgoHKZ6NVDt/Q9kQ1+On3b/l899RhE6C1SMAiQ0iB4sbkjA=="], - "@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.2.141", "", { "os": "darwin", "cpu": "x64" }, "sha512-4iAdarJaQ+2R58s6QJswZCzUdz2WQmL5lYG7Y+FLzWbRSROFfcH0QYpmOqSaPXd2KRQhIJwEacqecDZd/Q1XKQ=="], + "@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.215", "", { "os": "darwin", "cpu": "x64" }, "sha512-cyjfQgkgF/zZbSJP6uJpPXoIJE/gYFOgz+u/SjklvakcO56BpEnsbdl/oHVu5G8GCw69V11hKFZ8T8YsVOiv2w=="], - "@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.2.141", "", { "os": "linux", "cpu": "arm64" }, "sha512-Jdf0ZEwJzOP8sE6rPqdJN+SxMb0/L8sxJg4twCv/7S+Qzk0hJtls+wxSi+0Tjh6EEMaNxJqEGc7S3fx99Wi99Q=="], + "@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.215", "", { "os": "linux", "cpu": "arm64" }, "sha512-lb7ayxZeWLiEhlOjzF8oX+DdJHrVgR1hvwkwRdYo+LgTT3hSxv6h43sheS3hZ1I9LYvOTKWa2E0O1EnffOzyCg=="], - "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.2.141", "", { "os": "linux", "cpu": "arm64" }, "sha512-6H1AJ/AVaWNnV22kubUPkOTRzZFH0+qP9k7WlhriHMN9gtgZcVAsITMddDeGjQsQJMCAdhXFd6sgi7TM1LdeOQ=="], + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.215", "", { "os": "linux", "cpu": "arm64" }, "sha512-dXMR8afbZCFWUKQGyvn9swDYYvMtZWGqqbZ994ahS7HvGN4AgF63uvojHVErW1Xxn2601Bm+eCYQt+BSLk6iZQ=="], - "@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.2.141", "", { "os": "linux", "cpu": "x64" }, "sha512-DVjp72f3HmrRYpbneWZZWIqkUht5kTZXS7wXGFiwzLz6eNYEgjjh+GcsnhIi8UOwZUtNiKUrjZnoP38ovFqV8A=="], + "@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.3.215", "", { "os": "linux", "cpu": "x64" }, "sha512-Iivu3oq7hIEc81dpTu1W0GJ/kCE8TRtj9tb+wdZCp1grsuGEJiS3Bh1tLxCrhLOTDxPggK6xZGVN/RPJh84ywA=="], - "@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.2.141", "", { "os": "linux", "cpu": "x64" }, "sha512-fTI1YuM4cxOa4nSgsyMAdB5ELizkWp+w5Ispo4JnnYtcczMAL4D9GBNjWPW0sUzKvjsJOUVim68SmWLWhUOpXQ=="], + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.215", "", { "os": "linux", "cpu": "x64" }, "sha512-jSmrjSupnWtw8/I1Wmr32J6lB02gFXytmNbse4kcLEgH6UGtdZckKnDVnh/ejHma4QE9WGSn54xLsSFnjHVrRg=="], - "@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.2.141", "", { "os": "win32", "cpu": "arm64" }, "sha512-Wm10J6kfbufbPGFELokiJ/7Y5Oqug4Uag3HXFsV8g7TWCpaItx/oqVaJoiGptuAtXQB7xGLQVTuk082wER+Y5w=="], + "@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.215", "", { "os": "win32", "cpu": "arm64" }, "sha512-9Xtpwd4DzfObOycDkfYfQ7clhWoFu2fmRqmMZWyQRyk2mEHWR3gLBwUgpfjYb6m4Fke9eTmIx2lXDG2i1OaBzA=="], - "@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.2.141", "", { "os": "win32", "cpu": "x64" }, "sha512-IXuP29YJuWbR5Q6xOHrjFVGG54V2s1FC61UVNwEN5fpxL09MwPnbwtQL6fqgzt/U1MP7vWAwpXZriYAklkH/mg=="], + "@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.3.215", "", { "os": "win32", "cpu": "x64" }, "sha512-DkPwdc1zS6KIf6YNKXhlqAw95wnjG8Uh5bSXRrFA+MxsaWedlVFeja6zFM5uZ84ouGrcHEeU3PGUcGaKR1U4cQ=="], - "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.73.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-URURVzhxXGJDGUGFunIOtBlSl7KWvZiAAKY/ttTkZAkXT9bTPqdk2eK0b8qqSxXpikh3QKPnPYpiyX98zf5ebw=="], + "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.112.3", "", { "dependencies": { "json-schema-to-ts": "^3.1.1", "standardwebhooks": "^1.0.0" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-wjcozJlitVIuBEw9cj/xBuRznwkhcLmXmNzlFoeHbh4AvrDG3HGZrdvEOTTmobcbhjGkfOpKbmDTCQ4s9LQvCg=="], - "@ark/schema": ["@ark/schema@0.56.1", "", { "dependencies": { "@ark/util": "0.56.1" } }, "sha512-1Cf2g9nKD8K/3JGRu+gCCfYw5d4qR8YLLjDs5W5kpmaButCYWAPFUJqSXyBATPjglzCd4tIkp398iPYVs8MjRA=="], + "@ark/schema": ["@ark/schema@0.56.2", "", { "dependencies": { "@ark/util": "0.56.2" } }, "sha512-Qx4D2JFbBWpntiHZaTv7bGG4H/M2rigiknezKg/WVyDSaLdE4YCcWAOoFB7pjjDqHbbV2OqRfntm1nnXvwMexg=="], - "@ark/util": ["@ark/util@0.56.1", "", {}, "sha512-Tp1rTik3q5Z+jAeeDxr5JZpmVIw0miti1ykSEHyZv5Pw3TIJl2xbN6KTacOxITp0l3s9ytlrWd30Zvqcy5vzoQ=="], + "@ark/util": ["@ark/util@0.56.2", "", {}, "sha512-9kU2sUE38FZEGG7l3hamYMBieLYEJh2L1mrYD2eXpT+78EnQSV1bhjxJhnxGBMSTbtwpBSDNSK+K60WvaI/DTQ=="], "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], @@ -215,59 +217,65 @@ "@nodable/entities": ["@nodable/entities@2.2.0", "", {}, "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg=="], - "@oh-my-pi/hashline": ["@oh-my-pi/hashline@16.3.11", "", { "dependencies": { "diff": "^9.0.0", "lru-cache": "11.5.1" } }, "sha512-Sf3ueJ3CS0y4xlIpZEx4gWT/VIazdMoEV/BLuR4WKf1AicWXjtbEaLwWKwUzp81dqyReoKMWXAQiHG7iWyFMsg=="], + "@oh-my-pi/hashline": ["@oh-my-pi/hashline@17.0.5", "", { "dependencies": { "diff": "^9.0.0", "lru-cache": "11.5.2" } }, "sha512-1aFduPnzUAlnryx7JNttQi0SHstLaO4gPqFbdaSAM+UBeOXRo7W25q6h63xpKuvwBM8XabG3eZnkVLEaQ21InA=="], - "@oh-my-pi/omp-stats": ["@oh-my-pi/omp-stats@16.3.11", "", { "dependencies": { "@oh-my-pi/pi-ai": "16.3.11", "@oh-my-pi/pi-catalog": "16.3.11", "@oh-my-pi/pi-utils": "16.3.11", "@tailwindcss/node": "^4.3.0", "chart.js": "^4.5.1", "date-fns": "^4.4.0", "lucide-react": "^1.17.0", "react": "19.2.7", "react-chartjs-2": "^5.3.1", "react-dom": "19.2.7", "tailwindcss": "^4.3.0" }, "bin": { "omp-stats": "src/index.ts" } }, "sha512-CYaWxIIpgpUgbXPs1nzfljRuKB3OLyp3nkXRhM7Yfvg6MOsLBGV+cYj4i/y3eO4UXXmRl0m9YzLCYMdxYBvAaw=="], + "@oh-my-pi/omp-stats": ["@oh-my-pi/omp-stats@17.0.5", "", { "dependencies": { "@oh-my-pi/pi-ai": "17.0.5", "@oh-my-pi/pi-catalog": "17.0.5", "@oh-my-pi/pi-utils": "17.0.5", "@tailwindcss/node": "^4.3.2", "chart.js": "^4.5.1", "date-fns": "^4.4.0", "lucide-react": "^1.24.0", "react": "19.2.7", "react-chartjs-2": "^5.3.1", "react-dom": "19.2.7", "tailwindcss": "^4.3.2" }, "bin": { "omp-stats": "src/index.ts" } }, "sha512-ZHyHXC8x1In9dz/Rt4onS0mBC2fVgJLFB2+it8ry0IWX6OiGyzSpg/DinB0T+JiL0YHep1nLGC7d7BBz9vGK4g=="], - "@oh-my-pi/pi-agent-core": ["@oh-my-pi/pi-agent-core@16.3.11", "", { "dependencies": { "@oh-my-pi/pi-ai": "16.3.11", "@oh-my-pi/pi-catalog": "16.3.11", "@oh-my-pi/pi-natives": "16.3.11", "@oh-my-pi/pi-utils": "16.3.11", "@oh-my-pi/pi-wire": "16.3.11", "@oh-my-pi/snapcompact": "16.3.11", "@opentelemetry/api": "^1.9.1" } }, "sha512-LH+KMezlTzTzQv1bERw8jXspjBaz8dIJRTLgyNoLOIXdbmltXP6dsMHu8+bLKXhuUEmow4lP9FresUgwXFtqmQ=="], + "@oh-my-pi/pi-agent-core": ["@oh-my-pi/pi-agent-core@17.0.5", "", { "dependencies": { "@oh-my-pi/pi-ai": "17.0.5", "@oh-my-pi/pi-catalog": "17.0.5", "@oh-my-pi/pi-natives": "17.0.5", "@oh-my-pi/pi-utils": "17.0.5", "@oh-my-pi/pi-wire": "17.0.5", "@oh-my-pi/snapcompact": "17.0.5", "@opentelemetry/api": "^1.9.1" } }, "sha512-mnYqqr86f4UentSKXJA4nM8XS1YT7VxkG3COfLeH2kD7ri96znRFrEEpD+kjHjhaXLDj/x24jZ8Trtc6y5I1+Q=="], - "@oh-my-pi/pi-ai": ["@oh-my-pi/pi-ai@16.3.11", "", { "dependencies": { "@bufbuild/protobuf": "^2.12.0", "@oh-my-pi/pi-catalog": "16.3.11", "@oh-my-pi/pi-utils": "16.3.11", "@oh-my-pi/pi-wire": "16.3.11", "arktype": "^2.2.0", "zod": "^4" } }, "sha512-3uPvQSNcq+wgSKvix9+3TiSQUMMBJL02tOMu7StQUXU+uyz+1biYlyb2MbXFxSi1sAnFKRbqeCBM8rp2r1YQhQ=="], + "@oh-my-pi/pi-ai": ["@oh-my-pi/pi-ai@17.0.5", "", { "dependencies": { "@bufbuild/protobuf": "^2.12.1", "@oh-my-pi/pi-catalog": "17.0.5", "@oh-my-pi/pi-utils": "17.0.5", "@oh-my-pi/pi-wire": "17.0.5", "arktype": "2.2.3", "zod": "^4" } }, "sha512-6RtjXNDrz2V3IsBr3pw+FqHgBr08P61LeoW7UZE0ffMjHws9A2CYVfTXLsrMJyWOqn06AlNtxY4KORR/nTW/RA=="], - "@oh-my-pi/pi-catalog": ["@oh-my-pi/pi-catalog@16.3.11", "", { "dependencies": { "@bufbuild/protobuf": "^2.12.0", "@oh-my-pi/pi-utils": "16.3.11", "arktype": "^2.2.0", "zod": "^4" } }, "sha512-OpgL0DrkEcuDnyHsQvRmRCUcwt9Pz49uCQgEBKgtojembf+NVB6jwV2Q/YgFu6s7h3BYijQ6XzfT+lBHktD9Aw=="], + "@oh-my-pi/pi-catalog": ["@oh-my-pi/pi-catalog@17.0.5", "", { "dependencies": { "@bufbuild/protobuf": "^2.12.1", "@oh-my-pi/pi-utils": "17.0.5", "arktype": "2.2.3", "zod": "^4" } }, "sha512-OY0/EypQUHuUfR+li1fMAd5mbKD2XsIM7Ewe/DGnTlmwM/TCbkSPauTJTK7ilyCCmeuDKE9Qr9cVLqkB0KlNzQ=="], - "@oh-my-pi/pi-coding-agent": ["@oh-my-pi/pi-coding-agent@16.3.11", "", { "dependencies": { "@agentclientprotocol/sdk": "0.25.0", "@babel/parser": "^7.29.7", "@mozilla/readability": "^0.6.0", "@oh-my-pi/hashline": "16.3.11", "@oh-my-pi/omp-stats": "16.3.11", "@oh-my-pi/pi-agent-core": "16.3.11", "@oh-my-pi/pi-ai": "16.3.11", "@oh-my-pi/pi-catalog": "16.3.11", "@oh-my-pi/pi-mnemopi": "16.3.11", "@oh-my-pi/pi-natives": "16.3.11", "@oh-my-pi/pi-tui": "16.3.11", "@oh-my-pi/pi-utils": "16.3.11", "@oh-my-pi/pi-wire": "16.3.11", "@oh-my-pi/snapcompact": "16.3.11", "@opentelemetry/api": "^1.9.1", "@opentelemetry/context-async-hooks": "^2.7.1", "@opentelemetry/exporter-trace-otlp-proto": "^0.218.0", "@opentelemetry/resources": "^2.7.1", "@opentelemetry/sdk-trace-base": "^2.7.1", "@opentelemetry/sdk-trace-node": "^2.7.1", "@puppeteer/browsers": "^3.0.4", "@types/turndown": "5.0.6", "@xterm/headless": "^6.0.0", "arktype": "^2.2.0", "chalk": "^5.6.2", "diff": "^9.0.0", "fast-xml-parser": "^5.9.0", "handlebars": "^4.7.9", "linkedom": "^0.18.12", "lru-cache": "11.5.1", "mammoth": "^1.12.0", "mupdf": "^1.27.0", "puppeteer-core": "25.3.0", "turndown": "7.2.4", "turndown-plugin-gfm": "1.0.2", "zod": "^4" }, "optionalDependencies": { "@huggingface/transformers": "^4.2.0", "sherpa-onnx-node": "1.13.2" }, "bin": { "omp": "dist/cli.js" } }, "sha512-CqYS20xMia4xCAJcfssWrbwngytyldZzE+Dr8VCeV440fQ1kD7nBughn8xNFJ3ws4eVmaoJQyVxII4XBpteveg=="], + "@oh-my-pi/pi-coding-agent": ["@oh-my-pi/pi-coding-agent@17.0.5", "", { "dependencies": { "@agentclientprotocol/sdk": "1.2.1", "@babel/parser": "^7.29.7", "@mozilla/readability": "^0.6.0", "@oh-my-pi/hashline": "17.0.5", "@oh-my-pi/omp-stats": "17.0.5", "@oh-my-pi/pi-agent-core": "17.0.5", "@oh-my-pi/pi-ai": "17.0.5", "@oh-my-pi/pi-catalog": "17.0.5", "@oh-my-pi/pi-mnemopi": "17.0.5", "@oh-my-pi/pi-natives": "17.0.5", "@oh-my-pi/pi-tui": "17.0.5", "@oh-my-pi/pi-utils": "17.0.5", "@oh-my-pi/pi-wire": "17.0.5", "@oh-my-pi/snapcompact": "17.0.5", "@opentelemetry/api": "^1.9.1", "@opentelemetry/api-logs": "^0.220.0", "@opentelemetry/context-async-hooks": "^2.9.0", "@opentelemetry/exporter-logs-otlp-proto": "^0.220.0", "@opentelemetry/exporter-metrics-otlp-proto": "^0.220.0", "@opentelemetry/exporter-trace-otlp-proto": "^0.220.0", "@opentelemetry/resources": "^2.9.0", "@opentelemetry/sdk-logs": "^0.220.0", "@opentelemetry/sdk-metrics": "^2.9.0", "@opentelemetry/sdk-trace-base": "^2.9.0", "@opentelemetry/sdk-trace-node": "^2.9.0", "@puppeteer/browsers": "^3.0.6", "@types/turndown": "5.0.6", "@xterm/headless": "^6.0.0", "arktype": "2.2.3", "chalk": "^5.6.2", "diff": "^9.0.0", "fast-xml-parser": "^5.9.3", "handlebars": "^4.7.9", "header-generator": "^2.1.82", "linkedom": "^0.18.13", "lru-cache": "11.5.2", "mammoth": "^1.12.0", "mupdf": "^1.28.0", "puppeteer-core": "25.3.0", "turndown": "7.2.4", "turndown-plugin-gfm": "1.0.2", "zod": "^4" }, "optionalDependencies": { "@huggingface/transformers": "^4.2.0", "sherpa-onnx-node": "1.13.2" }, "bin": { "omp": "dist/cli.js" } }, "sha512-SdDYSuc1+zdoufN7xV6pResZXYEN0gpt1mjz7TwQH8LZroRpkA7JiLE48fQp0t3bJYMIKpuTjAXp1bZw2Qep4A=="], - "@oh-my-pi/pi-mnemopi": ["@oh-my-pi/pi-mnemopi@16.3.11", "", { "dependencies": { "@oh-my-pi/pi-ai": "16.3.11", "@oh-my-pi/pi-catalog": "16.3.11", "@oh-my-pi/pi-utils": "16.3.11", "lru-cache": "11.5.1" }, "peerDependencies": { "fastembed": "2.1.0", "onnxruntime-node": "1.21.0" }, "optionalPeers": ["fastembed", "onnxruntime-node"], "bin": { "mnemopi": "src/cli.ts" } }, "sha512-SC6zwjtYG+Xio5RY2k1HsA/+7iyh2nOcvtm12TQGrpavu4HZ14nNbago4g82JKo0dA35jBbkzjuhQbICdVRb6g=="], + "@oh-my-pi/pi-mnemopi": ["@oh-my-pi/pi-mnemopi@17.0.5", "", { "dependencies": { "@oh-my-pi/pi-ai": "17.0.5", "@oh-my-pi/pi-catalog": "17.0.5", "@oh-my-pi/pi-utils": "17.0.5", "lru-cache": "11.5.2" }, "peerDependencies": { "fastembed": "2.1.0", "onnxruntime-node": "1.21.0" }, "optionalPeers": ["fastembed", "onnxruntime-node"], "bin": { "mnemopi": "src/cli.ts" } }, "sha512-mR0NMvMWI8x35y00cdGwfaC8LFV7W1MHjS09VclHJE/NVdGo1Cn4OxhOXHDt+ayqfHch3RqWfhPrnzV31zSMog=="], - "@oh-my-pi/pi-natives": ["@oh-my-pi/pi-natives@16.3.11", "", { "optionalDependencies": { "@oh-my-pi/pi-natives-darwin-arm64": "16.3.11", "@oh-my-pi/pi-natives-darwin-x64": "16.3.11", "@oh-my-pi/pi-natives-linux-arm64": "16.3.11", "@oh-my-pi/pi-natives-linux-x64": "16.3.11", "@oh-my-pi/pi-natives-win32-x64": "16.3.11" } }, "sha512-E3V0L5KNNp3utr/pTYjZdgefX9AOcrs65aajja1ulfG6r+iOgo9nAKfnCwVmEVf7kOCZ+W/sTpA98MLVUXH07Q=="], + "@oh-my-pi/pi-natives": ["@oh-my-pi/pi-natives@17.0.5", "", { "optionalDependencies": { "@oh-my-pi/pi-natives-darwin-arm64": "17.0.5", "@oh-my-pi/pi-natives-darwin-x64": "17.0.5", "@oh-my-pi/pi-natives-linux-arm64": "17.0.5", "@oh-my-pi/pi-natives-linux-x64": "17.0.5", "@oh-my-pi/pi-natives-win32-x64": "17.0.5" } }, "sha512-nWuOVgytuiy3xFGDUK0TP0HMe+sRHOhyvXSAlc4aldrE2Z4cN3WM5CJN4OaVMxc+FR1qFBznzvvdP9K3EvHVLA=="], - "@oh-my-pi/pi-natives-darwin-arm64": ["@oh-my-pi/pi-natives-darwin-arm64@16.3.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RpmBIn5qSnB4nS98Y9MEk5hNUrYi+dwmBx9dnyIbR5VwR18rs286DOT/j/5K19+KTy9FCl4zqE9lvn1WMMfe1A=="], + "@oh-my-pi/pi-natives-darwin-arm64": ["@oh-my-pi/pi-natives-darwin-arm64@17.0.5", "", { "os": "darwin", "cpu": "arm64" }, "sha512-FaKzy1iB2SpbqZ16elvFpctYkJiRPs/Ve0mmpjuosXLim69ir2h+OOrAP1bmXADvK9zt1mElIRr1wQsX0kVk6Q=="], - "@oh-my-pi/pi-natives-darwin-x64": ["@oh-my-pi/pi-natives-darwin-x64@16.3.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-vKN2rxDTahM9UCwkEzBAr9uhFjMxGxIG9js9O1QeoxxaV9C7ZXupEpPgnvMs/utmGwtVYZ2GXEw/rXJP8XGjHg=="], + "@oh-my-pi/pi-natives-darwin-x64": ["@oh-my-pi/pi-natives-darwin-x64@17.0.5", "", { "os": "darwin", "cpu": "x64" }, "sha512-ayLls3BRHI0QmHe0pyycv8VOWSYCmm1oyDrdO9YXaSEdjS0doFB4qr+/Fz294Xpt3uSHvuBr1UvGdgvzbO3kNA=="], - "@oh-my-pi/pi-natives-linux-arm64": ["@oh-my-pi/pi-natives-linux-arm64@16.3.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-4WFev9f+B+qJZlIrOLF6KRA0TaYBjja7kvNCvBFiaR3QmPm6r8AyfW3WTgmdWmDrSItEW08AKgk0WQpfCCVF9A=="], + "@oh-my-pi/pi-natives-linux-arm64": ["@oh-my-pi/pi-natives-linux-arm64@17.0.5", "", { "os": "linux", "cpu": "arm64" }, "sha512-2G3KtSNPz8n+005UAqWk/gslDqd0oeS2unDsp5ItMJUTqGL6Yot869wHvdJRx4gVM5fgZJWG/04hTwd8G0gVxg=="], - "@oh-my-pi/pi-natives-linux-x64": ["@oh-my-pi/pi-natives-linux-x64@16.3.11", "", { "os": "linux", "cpu": "x64" }, "sha512-QMHC5Ggi3oOhe9iI1znwQbJ9Bwpd9SJm5DBJ+S7T0SwGGQ5C6U0RL16p7mOnX0gAkvVC0Yd/AxN6Nw+KwO5Tjw=="], + "@oh-my-pi/pi-natives-linux-x64": ["@oh-my-pi/pi-natives-linux-x64@17.0.5", "", { "os": "linux", "cpu": "x64" }, "sha512-O5HpCTj9dURsO6mhQyBikq0og6iRpCnai2nh0d3HZnD1qW/KYbKuf4Vtge09DsTEQwyvkywpnAuKP+sGYjy5XA=="], - "@oh-my-pi/pi-natives-win32-x64": ["@oh-my-pi/pi-natives-win32-x64@16.3.11", "", { "os": "win32", "cpu": "x64" }, "sha512-DWxSqcy69kkmVn5eACO0NgWXGNqxo5kc1XApiG/noVc8dgQ1Sowenv6LsCfwLne0/cJO9j6i5banVWKYIO7PkQ=="], + "@oh-my-pi/pi-natives-win32-x64": ["@oh-my-pi/pi-natives-win32-x64@17.0.5", "", { "os": "win32", "cpu": "x64" }, "sha512-Cev0XspoYBgJ4RbZJdavmUMDb1lJIL8xhWVaDzNMEstUaOHAzKTyYqbMLgV0c4vwSegfbRdxvInD+UOVnDDnAw=="], - "@oh-my-pi/pi-tui": ["@oh-my-pi/pi-tui@16.3.11", "", { "dependencies": { "@oh-my-pi/pi-natives": "16.3.11", "@oh-my-pi/pi-utils": "16.3.11", "lru-cache": "11.5.1", "marked": "^18.0.5" } }, "sha512-cEtnoeo7dz/7B7lrXoYeRb7unlW6dALSLQGi5YqorXVi9cep5In+CFgRKBRg7ZmmhqJxtqRlDTgND+lrBZSyNg=="], + "@oh-my-pi/pi-tui": ["@oh-my-pi/pi-tui@17.0.5", "", { "dependencies": { "@oh-my-pi/pi-natives": "17.0.5", "@oh-my-pi/pi-utils": "17.0.5", "lru-cache": "11.5.2", "marked": "^18.0.6" } }, "sha512-Z0U+G/SmwUHeXw94YRUmsNOGPMmtyffo/vYvm1blUe2uWBoCh7OSAgK5TcO3AxNPaK1CZAwKDzQ/8TM47is1uA=="], - "@oh-my-pi/pi-utils": ["@oh-my-pi/pi-utils@16.3.11", "", { "dependencies": { "@oh-my-pi/pi-natives": "16.3.11", "handlebars": "^4.7.9", "winston": "^3.19.0", "winston-daily-rotate-file": "^5.0.0" } }, "sha512-gQ/cjUmSjY9ry3OTfdTzCKxo5T3aC9/3/E4In0P/4n8FIyITQeObUk5QWo6j7YTzEdaXwJeo0zdCWhwlg6tC0g=="], + "@oh-my-pi/pi-utils": ["@oh-my-pi/pi-utils@17.0.5", "", { "dependencies": { "@oh-my-pi/pi-natives": "17.0.5", "handlebars": "^4.7.9", "winston": "^3.19.0", "winston-daily-rotate-file": "^5.0.0" } }, "sha512-f2ZR4mP7TuNUIQTBStlbDK/abZlvojPWVHTIDj8RRwGszg8k5nojgwC+MJt0MXRBUQmevbVXei008iALGeTSmQ=="], - "@oh-my-pi/pi-wire": ["@oh-my-pi/pi-wire@16.3.11", "", {}, "sha512-ABWqB5RFGAd9rDeQoW+Uys3xI4g6foaSPfjlWUXIUN8GJrqbY63BoHVLItwpJJBAY6n52GXWyBk8qdpKir73Nw=="], + "@oh-my-pi/pi-wire": ["@oh-my-pi/pi-wire@17.0.5", "", {}, "sha512-x6on+RyFEE74a3xQJ2JaHedJPLcvis0Kh+RVTb8kvRPhRqKMrkw9D3QkHyJZbiehk+qawxe0lMn5oahhMMwz2Q=="], - "@oh-my-pi/snapcompact": ["@oh-my-pi/snapcompact@16.3.11", "", { "dependencies": { "@oh-my-pi/pi-ai": "16.3.11", "@oh-my-pi/pi-natives": "16.3.11", "@oh-my-pi/pi-utils": "16.3.11", "@oh-my-pi/pi-wire": "16.3.11" } }, "sha512-yxBUkgSib3I23wv0XUH+LF5FMkxkR+BClhkL3DrFS2H0T8ZYTm3FYU6Bj9QVTuJs6l3RBn+g7hIkuGu7XKsUhw=="], + "@oh-my-pi/snapcompact": ["@oh-my-pi/snapcompact@17.0.5", "", { "dependencies": { "@oh-my-pi/pi-ai": "17.0.5", "@oh-my-pi/pi-natives": "17.0.5", "@oh-my-pi/pi-utils": "17.0.5", "@oh-my-pi/pi-wire": "17.0.5" } }, "sha512-5zqq4Ad0Wmy8S9SMuNj+9mCmpgfdNgkFxnF7xJjLeWcjxtiTKOrh0wu+Xk7LyxrVO0W/NWale2B1MAvVyKzIMA=="], "@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="], - "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.218.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-fmEWp5kXlGEc3i/lR698Hz41DfGyN4Tbe4g7L1AxSc7fF8Xeh/FQ9Quqpa9dVA413Q1Ad43QOLzU4JoXgbFPWw=="], + "@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.220.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w=="], "@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.9.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-OQ0vzvbZBiUhjqLnUaoNfYmP8553Crr3aggB4y0ZUi815mZ7idpdJXQmoKdeBKJelYttoBlLSSHubmyw3wvX4w=="], - "@opentelemetry/core": ["@opentelemetry/core@2.7.1", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-QAqIj32AtK6+pEVNG7EOVxHdE06RP+FM5qpiEJ4RtDcFIqKUZHYhl7/7UY5efhwmwNAg7j8QbJVBLxMerc0+gw=="], + "@opentelemetry/core": ["@opentelemetry/core@2.9.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw=="], - "@opentelemetry/exporter-trace-otlp-proto": ["@opentelemetry/exporter-trace-otlp-proto@0.218.0", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/otlp-exporter-base": "0.218.0", "@opentelemetry/otlp-transformer": "0.218.0", "@opentelemetry/resources": "2.7.1", "@opentelemetry/sdk-trace-base": "2.7.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-r1Msf8SNLRmwh9J6XQ5uh82D7CdDWMNHnPB7LAVHjzut0TkSeKc5KcIvr4SvHvfk/xwN5gxC+VLKQ1k0o8PSPw=="], + "@opentelemetry/exporter-logs-otlp-proto": ["@opentelemetry/exporter-logs-otlp-proto@0.220.0", "", { "dependencies": { "@opentelemetry/otlp-exporter-base": "0.220.0", "@opentelemetry/otlp-transformer": "0.220.0", "@opentelemetry/sdk-logs": "0.220.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-8LZAxdJ0ENDAFwr4j0oY35mHBltiSzvlhdQAPGiC7p9VnxtuSq4SW1gfBAdW6t6hiQG6OwUl8w7KHaOdJPKHWg=="], - "@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.218.0", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/otlp-transformer": "0.218.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-ZwqpkNL5W7RyGJPDZ9g06DvKp8KFTWPJPN12anpMQYSKpTSU0z3EIZuPq9vPGpS8siFyOqDYDAuCwlNO9FqgbA=="], + "@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.220.0", "", { "dependencies": { "@opentelemetry/core": "2.9.0", "@opentelemetry/otlp-exporter-base": "0.220.0", "@opentelemetry/otlp-transformer": "0.220.0", "@opentelemetry/resources": "2.9.0", "@opentelemetry/sdk-metrics": "2.9.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Yqt3RBw/bRVncaE9qIIhk4WfjbAQqXuP9FgAaU+IKPndnLEp/cUqZlSC324+bpmduRz7DoTjig8Ub0PeILWXUA=="], - "@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.218.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.218.0", "@opentelemetry/core": "2.7.1", "@opentelemetry/resources": "2.7.1", "@opentelemetry/sdk-logs": "0.218.0", "@opentelemetry/sdk-metrics": "2.7.1", "@opentelemetry/sdk-trace-base": "2.7.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CFaKH87WAzjuJ4awowTTLzUvMfaRfiOFG5+qm5S5ncyalRtN4ecQ+YmuANJSCrVPuvZFEkUgKhBPBndxi3rHsQ=="], + "@opentelemetry/exporter-metrics-otlp-proto": ["@opentelemetry/exporter-metrics-otlp-proto@0.220.0", "", { "dependencies": { "@opentelemetry/core": "2.9.0", "@opentelemetry/exporter-metrics-otlp-http": "0.220.0", "@opentelemetry/otlp-exporter-base": "0.220.0", "@opentelemetry/otlp-transformer": "0.220.0", "@opentelemetry/resources": "2.9.0", "@opentelemetry/sdk-metrics": "2.9.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lyO+IQBdSvqHN/ZOW/OzrSWemtfD+HgWngn+HBNLhjy0YrCQQTz0OE/kSekH2Pl340dn9DWzhqHdz5Eftr+HLA=="], + + "@opentelemetry/exporter-trace-otlp-proto": ["@opentelemetry/exporter-trace-otlp-proto@0.220.0", "", { "dependencies": { "@opentelemetry/core": "2.9.0", "@opentelemetry/otlp-exporter-base": "0.220.0", "@opentelemetry/otlp-transformer": "0.220.0", "@opentelemetry/resources": "2.9.0", "@opentelemetry/sdk-trace": "2.9.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-voTAD8XgJxlK7zLkXh8EzMB09zrQr3tyY/BsnDTlDiQU/UdK58MZ63A3mUjdEDrxMjCVmBHU3WQJhRmQe+Dvzg=="], + + "@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.220.0", "", { "dependencies": { "@opentelemetry/core": "2.9.0", "@opentelemetry/otlp-transformer": "0.220.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ=="], + + "@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.220.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.220.0", "@opentelemetry/core": "2.9.0", "@opentelemetry/resources": "2.9.0", "@opentelemetry/sdk-logs": "0.220.0", "@opentelemetry/sdk-metrics": "2.9.0", "@opentelemetry/sdk-trace": "2.9.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A=="], "@opentelemetry/resources": ["@opentelemetry/resources@2.9.0", "", { "dependencies": { "@opentelemetry/core": "2.9.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg=="], - "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.218.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.218.0", "@opentelemetry/core": "2.7.1", "@opentelemetry/resources": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-QvnNdugatFTVCJXH0Mcu7GOOJSylA9j127kIezOE4YwTI4YbowRons2K4WZTv5FMS8T4q9P0NdaRHdkSmeAIag=="], + "@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.220.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.220.0", "@opentelemetry/core": "2.9.0", "@opentelemetry/resources": "2.9.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA=="], - "@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/resources": "2.7.1" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-MpDJdkiFDs3Pm1RHO3KByuZbuBdJEXEAkiC0+yJdsZGVCdf1RpHR6n+LHDcS7ffmfrt5kVCzJSCfm4z2C7v0uQ=="], + "@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.9.0", "", { "dependencies": { "@opentelemetry/core": "2.9.0", "@opentelemetry/resources": "2.9.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q=="], "@opentelemetry/sdk-trace": ["@opentelemetry/sdk-trace@2.9.0", "", { "dependencies": { "@opentelemetry/core": "2.9.0", "@opentelemetry/resources": "2.9.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw=="], @@ -297,8 +305,12 @@ "@puppeteer/browsers": ["@puppeteer/browsers@3.0.6", "", { "dependencies": { "modern-tar": "^0.7.6", "yargs": "^18.0.0" }, "peerDependencies": { "proxy-agent": ">=8.0.1", "yauzl": "^2.10.0 || ^3.4.0" }, "optionalPeers": ["proxy-agent", "yauzl"], "bin": { "browsers": "lib/main-cli.js" } }, "sha512-B/gKoqlFkzhvzsI6jo9K1cZz9o5ypviVv/xu8CwA4grZzyVwN+XfkT+tu8T1zrauuEXv6VhS2oGX+6NL95WcKA=="], + "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], + "@so-ric/colorspace": ["@so-ric/colorspace@1.1.6", "", { "dependencies": { "color": "^5.0.2", "text-hex": "1.0.x" } }, "sha512-/KiKkpHNOBgkFJwu9sh48LkHSMYGyuTcSFK/qMBdnOAlrRJzRSXAOFB5qwzaVQuDl8wAvHVMkaASQDReTahxuw=="], + "@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="], + "@tailwindcss/node": ["@tailwindcss/node@4.3.2", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "5.21.6", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.2" } }, "sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg=="], "@types/node": ["@types/node@24.13.2", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-fRa09kZTgu8o71KFcDjUFuc7F+dEbZYZmkI0mg5YBTRs0yMKjYHsq/c0urDKeDb+D5qVgXOdFcuu+DZPKOITwA=="], @@ -327,28 +339,36 @@ "argparse": ["argparse@1.0.10", "", { "dependencies": { "sprintf-js": "~1.0.2" } }, "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="], - "arkregex": ["arkregex@0.0.7", "", { "dependencies": { "@ark/util": "0.56.1" } }, "sha512-O/Ltrn9EUSn3ui0KVzfyrWGDUsHlzKxDVBtpQxL/6JmLRMAZAebfSNf/A/J5Ny5S6QIwrXX+RfXsu888HMs35A=="], + "arkregex": ["arkregex@0.0.8", "", { "dependencies": { "@ark/util": "0.56.2" } }, "sha512-PJcx6G1kQTgLKPUbeYlYecDRaKq15AMSGVajlKFYWlPeJRQL+j3dKE6tyMs40HZ99djS1l9Vhl3ezAHy9JBIqQ=="], - "arktype": ["arktype@2.2.2", "", { "dependencies": { "@ark/schema": "0.56.1", "@ark/util": "0.56.1", "arkregex": "0.0.7" } }, "sha512-YYf1xhL2dh5aPZFlsY0RAsxv5HZqfLGLptH2ZP3JidTmsGRW8VOymhPjjMTkerL12vR2YtX0SK4c1mATtae8SA=="], + "arktype": ["arktype@2.2.3", "", { "dependencies": { "@ark/schema": "0.56.2", "@ark/util": "0.56.2", "arkregex": "0.0.8" } }, "sha512-7W+0RLTUNJiBFIIZXwOQxSR8Z273IAd6IvqBeG9+gHnQKFsIx2C0iOtGTmMrPnlX4qLXyc5+ll7A0BIj9WrbTg=="], "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.43", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ=="], + "bluebird": ["bluebird@3.4.7", "", {}, "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA=="], "body-parser": ["body-parser@2.3.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", "debug": "^4.4.3", "http-errors": "^2.0.1", "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", "qs": "^6.15.2", "raw-body": "^3.0.2", "type-is": "^2.1.0" } }, "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw=="], - "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + "boolbase": ["boolbase@2.0.0", "", {}, "sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA=="], "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], + "browserslist": ["browserslist@4.28.6", "", { "dependencies": { "baseline-browser-mapping": "^2.10.42", "caniuse-lite": "^1.0.30001803", "electron-to-chromium": "^1.5.389", "node-releases": "^2.0.51", "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw=="], + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001806", "", {}, "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw=="], + "cc-session-io": ["cc-session-io@0.3.1", "", { "bin": { "cc-session": "dist/cli.js" } }, "sha512-FPswREdPLqetYkmdUTF36NVGzjyrhUJ8PzP9wLraoL/54q9Q72dHC8PCc/OhF/bH3n0M5iO/2SRGfMwZZZaDgQ=="], "chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="], @@ -383,9 +403,9 @@ "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], - "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", "domhandler": "^5.0.2", "domutils": "^3.0.1", "nth-check": "^2.0.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + "css-select": ["css-select@7.0.0", "", { "dependencies": { "boolbase": "^2.0.0", "css-what": "^8.0.0", "domhandler": "^6.0.1", "domutils": "^4.0.2", "nth-check": "^3.0.1" } }, "sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g=="], - "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + "css-what": ["css-what@8.0.0", "", {}, "sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw=="], "cssom": ["cssom@0.5.0", "", {}, "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw=="], @@ -409,13 +429,15 @@ "dingbat-to-unicode": ["dingbat-to-unicode@1.0.1", "", {}, "sha512-98l0sW87ZT58pU4i61wa2OHwxbiYSbuxsCBozaVnYX2iCnr3bLM3fIes1/ej7h1YdOKuKt/MLs706TVnALA65w=="], - "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + "dom-serializer": ["dom-serializer@3.1.1", "", { "dependencies": { "domelementtype": "^3.0.0", "domhandler": "^6.0.0", "entities": "^8.0.0" } }, "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw=="], "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], - "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + "domhandler": ["domhandler@6.0.1", "", { "dependencies": { "domelementtype": "^3.0.0" } }, "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg=="], - "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + "domutils": ["domutils@4.0.2", "", { "dependencies": { "dom-serializer": "^3.0.0", "domelementtype": "^3.0.0", "domhandler": "^6.0.0" } }, "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA=="], + + "dot-prop": ["dot-prop@6.0.1", "", { "dependencies": { "is-obj": "^2.0.0" } }, "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA=="], "duck": ["duck@0.1.12", "", { "dependencies": { "underscore": "^1.13.1" } }, "sha512-wkctla1O6VfP89gQ+J/yDesM0S7B7XLXjKGzXxMDVFg7uEn706niAtyYovKbyq1oT9YwDcly721/iUWoc8MVRg=="], @@ -423,6 +445,8 @@ "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + "electron-to-chromium": ["electron-to-chromium@1.5.393", "", {}, "sha512-kiDJdIUawuEIcp9XoICKp1iTYDEbgguIPq526N1Q7jIQDeQ3CqoMx71025PI/7E48Ddtw2HuWsVjY7afEgNxmg=="], + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], "enabled": ["enabled@2.0.0", "", {}, "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ=="], @@ -461,6 +485,8 @@ "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-sha256": ["fast-sha256@1.3.0", "", {}, "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ=="], + "fast-uri": ["fast-uri@3.1.3", "", {}, "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg=="], "fast-xml-builder": ["fast-xml-builder@1.2.1", "", { "dependencies": { "path-expression-matcher": "^1.5.0", "xml-naming": "^0.1.0" } }, "sha512-tPb5TTWfgfVx5BNSi2xV0eLr89POeXXn0dXIsCJ9m1narrWxeIyx6je9d7Rce/3NyXLbvuQmLkxq+RuxMWejvw=="], @@ -485,6 +511,8 @@ "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + "generative-bayesian-network": ["generative-bayesian-network@2.1.83", "", { "dependencies": { "adm-zip": "^0.5.9", "tslib": "^2.4.0" } }, "sha512-LssI9es+oUoezoHloFGw0Hts0YEfujjBOE8KNl70oBt4HPjD/4rpUqcgZ/M7RCmgKvkmCyPB2KWowyJHuKyhfw=="], + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], @@ -511,6 +539,8 @@ "hasown": ["hasown@2.0.4", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A=="], + "header-generator": ["header-generator@2.1.82", "", { "dependencies": { "browserslist": "^4.21.1", "generative-bayesian-network": "^2.1.82", "ow": "^0.28.1", "tslib": "^2.4.0" } }, "sha512-4NjPB0+bAKjPoponSmTOkK58IEF2W22sOJA5O48k/MxbCZgOm+jrU4WVR53Z2I6xFgIPkVrQmKtt1LAbWtfqXw=="], + "hono": ["hono@4.12.28", "", {}, "sha512-YwUvVpSF7m1yOblFPrU3Hbo8XhPheBoiyfGuII6z19LnOr6JpDnyyp7LFNrfV56wS8tpvtBFGRISHN02pDdLOA=="], "html-escaper": ["html-escaper@3.0.3", "", {}, "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ=="], @@ -529,6 +559,8 @@ "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + "is-obj": ["is-obj@2.0.0", "", {}, "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="], + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], @@ -581,7 +613,9 @@ "lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="], - "linkedom": ["linkedom@0.18.12", "", { "dependencies": { "css-select": "^5.1.0", "cssom": "^0.5.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.0.0", "uhyphen": "^0.2.0" }, "peerDependencies": { "canvas": ">= 2" }, "optionalPeers": ["canvas"] }, "sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q=="], + "linkedom": ["linkedom@0.18.13", "", { "dependencies": { "css-select": "^7.0.0", "cssom": "^0.5.0", "html-escaper": "^3.0.3", "htmlparser2": "^10.1.0", "uhyphen": "^0.2.0" }, "peerDependencies": { "canvas": ">= 2" }, "optionalPeers": ["canvas"] }, "sha512-ES/o9qotMpzpN2MHs+Iq/JcVoOj8Fa5wiQYrTdFpvAnwXL0g66XHHUc9WUMk6nAlBtGsFQ24ne+SYnvnaQ2FSw=="], + + "lodash.isequal": ["lodash.isequal@4.5.0", "", {}, "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="], "logform": ["logform@2.7.0", "", { "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" } }, "sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ=="], @@ -589,15 +623,15 @@ "lop": ["lop@0.4.2", "", { "dependencies": { "duck": "^0.1.12", "option": "~0.2.1", "underscore": "^1.13.1" } }, "sha512-RefILVDQ4DKoRZsJ4Pj22TxE3omDO47yFpkIBoDKzkqPRISs5U1cnAdg/5583YPkWPaLIYHOKRMQSvjFsO26cw=="], - "lru-cache": ["lru-cache@11.5.1", "", {}, "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A=="], + "lru-cache": ["lru-cache@11.5.2", "", {}, "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g=="], - "lucide-react": ["lucide-react@1.23.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-38BpJcD0JhFosxHApP/BYsBetLpQFRoTRzEzstM/XCc3jsAG7wqaY1lgVwxiUe3xqYE+lNxo2PkCmYwXWrwwIw=="], + "lucide-react": ["lucide-react@1.25.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-/mdJTRbiwcLOQ1NZZK1amZF9rIZyvO18D6r9TngE6TG1NmqHgFuT4eE7Xrkm9UsXMbBJD1NlfwHVltCDWHrOTw=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], "mammoth": ["mammoth@1.12.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.6", "argparse": "~1.0.3", "base64-js": "^1.5.1", "bluebird": "~3.4.0", "dingbat-to-unicode": "^1.0.1", "jszip": "^3.7.1", "lop": "^0.4.2", "path-is-absolute": "^1.0.0", "underscore": "^1.13.1", "xmlbuilder": "^10.0.0" }, "bin": { "mammoth": "bin/mammoth" } }, "sha512-cwnK1RIcRdDMi2HRx2EXGYlxqIEh0Oo3bLhorgnsVJi2UkbX1+jKxuBNR9PC5+JaX7EkmJxFPmo6mjLpqShI2w=="], - "marked": ["marked@18.0.5", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w=="], + "marked": ["marked@18.0.6", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-MrV5puXBfuiy6wl6DLaq3BtIJQAJToAd5zt/ZKhRfGRAuFPALE7/4Y7jnxRQoEgK/pBgurGqLyAuRgZ2xOjr6w=="], "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], @@ -627,7 +661,9 @@ "neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="], - "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "^1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + "node-releases": ["node-releases@2.0.51", "", {}, "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ=="], + + "nth-check": ["nth-check@3.0.1", "", { "dependencies": { "boolbase": "^2.0.0" } }, "sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ=="], "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], @@ -651,6 +687,8 @@ "option": ["option@0.2.4", "", {}, "sha512-pkEqbDyl8ou5cpq+VsnQbe/WlEy5qS7xPzMS1U55OCG9KPvwFD46zDbxQIj3egJSFc3D+XhYOPUzz49zQAVy7A=="], + "ow": ["ow@0.28.2", "", { "dependencies": { "@sindresorhus/is": "^4.2.0", "callsites": "^3.1.0", "dot-prop": "^6.0.1", "lodash.isequal": "^4.5.0", "vali-date": "^1.0.0" } }, "sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q=="], + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], @@ -663,6 +701,8 @@ "path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="], + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + "pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="], "platform": ["platform@1.3.6", "", {}, "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="], @@ -753,6 +793,8 @@ "stack-trace": ["stack-trace@0.0.10", "", {}, "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg=="], + "standardwebhooks": ["standardwebhooks@1.0.0", "", { "dependencies": { "@stablelib/base64": "^1.0.0", "fast-sha256": "^1.3.0" } }, "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg=="], + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], "string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], @@ -803,8 +845,12 @@ "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + "vali-date": ["vali-date@1.0.0", "", {}, "sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg=="], + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], "webdriver-bidi-protocol": ["webdriver-bidi-protocol@0.4.2", "", {}, "sha512-VSV+fzfChirL3e7jay2yUC7B4HQCGtEWEg/MSSQbK+qWbqeGlRLlXTzPpYr3XGUvbpDHumWZBJxgesg4N7dbtA=="], @@ -839,33 +885,21 @@ "zod-to-json-schema": ["zod-to-json-schema@3.25.2", "", { "peerDependencies": { "zod": "^3.25.28 || ^4" } }, "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA=="], - "@anthropic-ai/claude-agent-sdk/@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.93.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-q9vaSZQVFx6B/gPxetGYfLXSJD5v0sOmh0OpZDq7yCrTSA+Rscvrtyol7JJTW40wEpQB4U1B4JXzxQitbQ3CAA=="], - - "@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/resources": ["@opentelemetry/resources@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ=="], - - "@opentelemetry/exporter-trace-otlp-proto/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/resources": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw=="], - - "@opentelemetry/otlp-transformer/@opentelemetry/resources": ["@opentelemetry/resources@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ=="], - - "@opentelemetry/otlp-transformer/@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/resources": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-NAYIlsF8MPUsKqJMiDQJTMPOmlbawC1Iz/omMLygZ1C9am8fTKYjTaI+OZM+WTY3t3Glo0wnOg/6/pac6RGPPw=="], - - "@opentelemetry/resources/@opentelemetry/core": ["@opentelemetry/core@2.9.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw=="], - - "@opentelemetry/sdk-logs/@opentelemetry/resources": ["@opentelemetry/resources@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ=="], + "body-parser/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], - "@opentelemetry/sdk-metrics/@opentelemetry/resources": ["@opentelemetry/resources@2.7.1", "", { "dependencies": { "@opentelemetry/core": "2.7.1", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-DeT6KKolmC4e/dRQvMQ/RwlnzhaqeiFOXY5ngoOPJ07GgVVKxZOg9EcrNZb5aTzUn+iCrJldAgOfQm1O/QfPAQ=="], + "chromium-bidi/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], - "@opentelemetry/sdk-trace/@opentelemetry/core": ["@opentelemetry/core@2.9.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw=="], + "dom-serializer/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="], - "@opentelemetry/sdk-trace-base/@opentelemetry/core": ["@opentelemetry/core@2.9.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw=="], + "dom-serializer/entities": ["entities@8.0.0", "", {}, "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA=="], - "@opentelemetry/sdk-trace-node/@opentelemetry/core": ["@opentelemetry/core@2.9.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw=="], + "domhandler/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="], - "body-parser/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + "domutils/domelementtype": ["domelementtype@3.0.0", "", {}, "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg=="], - "chromium-bidi/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "htmlparser2/domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "^2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], - "dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + "htmlparser2/domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", "domhandler": "^5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], "jszip/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], @@ -877,6 +911,10 @@ "type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="], + "htmlparser2/domutils/dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + "jszip/readable-stream/string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "htmlparser2/domutils/dom-serializer/entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], } } diff --git a/claude-bridge.example.json b/claude-bridge.example.json index 922213e..c4b3560 100644 --- a/claude-bridge.example.json +++ b/claude-bridge.example.json @@ -5,9 +5,6 @@ "defaultIsolated": false }, "provider": { - "contextWindow": "auto", - "plan": "pro", - "longContextExtraUsage": false, "strictMcpConfig": true } } diff --git a/documentation/completed/improvements/2026-07-19_omp-cloud-bridge-compatibility.md b/documentation/completed/improvements/2026-07-19_omp-cloud-bridge-compatibility.md new file mode 100644 index 0000000..46776a3 --- /dev/null +++ b/documentation/completed/improvements/2026-07-19_omp-cloud-bridge-compatibility.md @@ -0,0 +1,73 @@ +# Task: OMP Cloud Bridge Compatibility +**Date Started**: 2026-07-19 +**Status**: Complete +**Agent Lead**: ⚙️ + +## Plan +### Objective +Stabilize `omp-claude-bridge` against OMP 17.0.5 and Claude Agent SDK 0.3.215 / Claude Code 2.1.215. Prevent the provider from disappearing after subagent initialization, expose only canonical OMP model entries, delegate context control to `omp-ccwindow`, and leave authentication entirely to the official Agent SDK. + +### Approach +- Register the provider on every extension initialization while preserving the first process-global `streamSimple` owner. +- Release that owner only on `session_shutdown`; ordinary session lifecycle events reset session state only. +- Remove bridge-owned context variants, routing, plan metadata, and model aliases. +- Preserve canonical OMP Anthropic model metadata and pass canonical IDs to Agent SDK queries. +- Keep authentication pass-through: no bridge login, token storage, credential inspection, or credential injection. +- Align Claude and OMP dependencies with the approved versions and refresh the live plugin link. + +### Tasks +- ✅ Fix provider registration lifecycle and add its regression test. +- ✅ Replace context-window variants with canonical model registration and tests. +- ✅ Remove entitlement/context config and document the authentication boundary. +- ✅ Upgrade Agent SDK, peers, and OMP dependencies. +- ✅ Run install, typecheck, unit, version, plugin, model-surface, authentication, and context-plugin verification. +- ✅ Run focused code review and silent-failure review. + +## Implementation Log +### 2026-07-19 - Plan Approved +- **Changes Made**: Recorded the approved compatibility plan for execution. +- **Files Modified**: `documentation/planned/improvements/2026-07-19_omp-cloud-bridge-compatibility.md` +- **Decisions**: OMP owns the native picker; `omp-ccwindow` owns runtime context display/compaction overrides; the official Agent SDK owns authentication. +- **Notes for Next Engineer**: The authoritative detailed plan is `local://omp-cloud-bridge-compatibility-plan.md` for this session. + +### 2026-07-19 - Provider Registration Lifecycle Complete +- **Changes Made**: Added a process-global stream owner helper that queues `registerProvider` on every extension initialization and releases ownership only when the owning stream shuts down. Split ordinary session resets from provider stream release. +- **Files Modified**: `src/provider-registration.ts`, `src/index.ts`, `tests/unit-provider-registration.mjs` +- **Decisions**: Later subagent module instances reuse the first stream function but still register, matching OMP 17's source-clearing loader lifecycle. +- **Verification**: Focused provider registration test passed; `bun run typecheck` passed. +- **Notes for Next Engineer**: Non-owner release is a no-op; owner release permits a fresh module instance to acquire the stream key. + +### 2026-07-19 - Canonical Models Complete +- **Changes Made**: Removed context variants and Claude Code model rewrites. Canonical OMP catalog entries now retain provider-model metadata while source routing fields are omitted so the bridge's custom stream handler remains authoritative. Canonical IDs pass directly to provider, compaction, and AskClaude queries. Replaced variant tests with canonical model tests. +- **Files Modified**: `src/models.ts`, `src/index.ts`, `src/config.ts`, `claude-bridge.example.json`, `tests/unit-models.mjs`; removed `tests/unit-context-window.mjs` +- **Decisions**: `omp-ccwindow` is the sole user-facing OMP context override. The bridge does not infer API capacity or account entitlements. +- **Verification**: Four focused model tests and `bun run typecheck` passed; removed routing symbols have no remaining callsites. +- **Notes for Next Engineer**: OMP provider-model metadata, including thinking capabilities and cost fields, is preserved; `api`, `provider`, and `baseUrl` are intentionally stripped to prevent bypassing `streamSimple`. + +### 2026-07-19 - Authentication Pass-through Complete +- **Changes Made**: Removed every Agent SDK `env` option, entitlement config, and credential-adjacent routing. Rewrote README/package metadata to document SDK-owned authentication, subscription/API billing, and Anthropic's current third-party policy boundary. +- **Files Modified**: `src/index.ts`, `src/config.ts`, `claude-bridge.example.json`, `README.md`, `package.json` +- **Decisions**: The bridge supplies no environment or credential material to `query()`; Claude Code inherits and resolves parent authentication itself. +- **Verification**: Credential-handling grep returned no source/test/example callsites; `bun run typecheck` and the full 12-test pre-upgrade suite passed. Both linked Anthropic policy pages were read and matched the documented claims. +- **Notes for Next Engineer**: Existing local login currently uses subscription quota; `ANTHROPIC_API_KEY` uses API billing; policy is explicitly documented as subject to Anthropic change. + +### 2026-07-19 - Dependency Alignment Complete +- **Changes Made**: Upgraded Claude Agent SDK to 0.3.215, its direct peers to Anthropic SDK 0.112.3, MCP SDK 1.29.0, and Zod 4.4.3; aligned all OMP development packages and peer minimums to 17.0.5; refreshed `bun.lock`. +- **Files Modified**: `package.json`, `bun.lock` +- **Decisions**: Kept OMP's legacy pi-ai shim imports because OMP 17.0.5 exports and supports them. Left the inactive upstream Pi bridge snapshot untouched. +- **Verification**: `bun install`, `bun run typecheck`, and all 12 unit tests passed. `npm list` resolved all four direct SDK packages without peer errors. Claude Code and Agent SDK both report 2.1.215 parity. +- **Notes for Next Engineer**: The 0.3.142 deprecated v2 session API removal does not affect this repository; it uses `query()`. + +### 2026-07-19 - Compatibility Verification Complete +- **Changes Made**: Refreshed only the live OMP bridge link and exercised provider registration, model discovery, local-login authentication, debug logging, and `omp-ccwindow` compatibility. +- **Files Modified**: OMP plugin lock metadata under `~/.omp/plugins`; no `omp-ccwindow` or inactive Pi bridge files changed. +- **Decisions**: Source catalog routing fields are not provider metadata. Preserving Anthropic's `api`, `provider`, or `baseUrl` bypassed `streamSimple` and produced an OMP-side invalid-bearer response; projecting only `ProviderModelConfig` fields fixed the root cause. +- **Verification**: OMP lists one enabled bridge and one enabled `omp-ccwindow`, doctor reports both healthy, the refreshed lock records bridge 0.8.1, and the model surface has seven canonical entries with intact catalog limits and no aliases or labels. With `ANTHROPIC_API_KEY` unset, a debug-enabled Haiku request returned `BRIDGE_AUTH_OK`; bridge/CLI diagnostics contained no credential strings. `omp-ccwindow` typecheck and six tests passed, its source only clones `contextWindow` and calls `setModel`, and the combined bridge model count remains seven. +- **Notes for Next Engineer**: Authentication remained inside Claude Code; the bridge query path emitted `provider: fresh query` and completed normally under the existing local login. + +### 2026-07-19 - Review Complete +- **Changes Made**: Ran CodeRabbit, focused lifecycle/model review, code simplification review, and silent-failure review. Restored non-credential Claude Code controls through inherited `process.env` so OMP remains the sole compaction owner and cloud MCP auto-discovery stays disabled without supplying `query()` an env object. +- **Files Modified**: `src/index.ts`, `README.md`, `documentation/active/2026-07-19_omp-cloud-bridge-compatibility.md` +- **Decisions**: Accepted the focused review's autocompaction/cloud-MCP finding and fixed it at extension initialization. Rejected the silent-review suggestion to throw on missing catalog IDs because the approved contract explicitly requires missing IDs to be omitted and tests defend that behavior. +- **Verification**: Initial CodeRabbit review reported zero findings. Focused review found one high-confidence control regression; its targeted re-review returned `Resolved; no findings`. The code simplifier made no changes. The named silent-failure agent could not start because the subagent harness had no selected model, so the same review was completed against the full diff with the slow reviewer; it produced only the contract-conflicting missing-ID suggestion. After the accepted fix, `bun run typecheck`, all 12 unit tests, and a headless local-login smoke returning `BRIDGE_REVIEW_OK` passed. A second CodeRabbit run was attempted but rate-limited for 38 minutes. +- **Notes for Next Engineer**: `query()` intentionally has no `env` field. The extension sets only `CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC`, `DISABLE_AUTO_COMPACT`, and `ENABLE_CLAUDEAI_MCP_SERVERS` before any query; authentication variables are neither read nor rewritten. diff --git a/package.json b/package.json index ea22c96..df6263b 100644 --- a/package.json +++ b/package.json @@ -2,15 +2,13 @@ "name": "omp-claude-bridge", "version": "0.8.1", "private": false, - "description": "Oh My Pi extension that runs Claude Code (via the Claude Agent SDK) as a model provider, adds an AskClaude delegation tool, and lets you force the 1M / 200K context window per provider.", + "description": "Oh My Pi extension that runs Claude Code through the official Claude Agent SDK as a model provider and AskClaude delegation tool.", "keywords": [ "omp-package", "oh-my-pi", "extension", "claude-code", - "claude-agent-sdk", - "context-window", - "1m-context" + "claude-agent-sdk" ], "author": "Jonathan Borgwing (https://github.com/DevVig)", "contributors": [ @@ -43,18 +41,20 @@ }, "type": "module", "dependencies": { - "@anthropic-ai/claude-agent-sdk": "^0.2.141", - "@anthropic-ai/sdk": "^0.73.0", + "@anthropic-ai/claude-agent-sdk": "^0.3.215", + "@anthropic-ai/sdk": "^0.112.3", + "@modelcontextprotocol/sdk": "^1.29.0", "cc-session-io": "^0.3.1", "change-case": "^5.4.4", - "typebox": "^1.3.0" + "typebox": "^1.3.0", + "zod": "^4.4.3" }, "peerDependencies": { - "@oh-my-pi/pi-ai": ">=16.3.6", - "@oh-my-pi/pi-agent-core": ">=16.3.6", - "@oh-my-pi/pi-coding-agent": ">=16.3.6", - "@oh-my-pi/pi-tui": ">=16.3.6", - "@oh-my-pi/pi-utils": ">=16.3.6" + "@oh-my-pi/pi-ai": ">=17.0.5", + "@oh-my-pi/pi-agent-core": ">=17.0.5", + "@oh-my-pi/pi-coding-agent": ">=17.0.5", + "@oh-my-pi/pi-tui": ">=17.0.5", + "@oh-my-pi/pi-utils": ">=17.0.5" }, "peerDependenciesMeta": { "@oh-my-pi/pi-ai": { @@ -74,11 +74,11 @@ } }, "devDependencies": { - "@oh-my-pi/pi-ai": "^16.3.6", - "@oh-my-pi/pi-agent-core": "^16.3.6", - "@oh-my-pi/pi-coding-agent": "^16.3.6", - "@oh-my-pi/pi-tui": "^16.3.6", - "@oh-my-pi/pi-utils": "^16.3.6", + "@oh-my-pi/pi-ai": "^17.0.5", + "@oh-my-pi/pi-agent-core": "^17.0.5", + "@oh-my-pi/pi-coding-agent": "^17.0.5", + "@oh-my-pi/pi-tui": "^17.0.5", + "@oh-my-pi/pi-utils": "^17.0.5", "@types/node": "^24.13.2", "tsx": "^4.22.4", "typescript": "^6.0.3" diff --git a/src/config.ts b/src/config.ts index b38d27f..bb0487a 100644 --- a/src/config.ts +++ b/src/config.ts @@ -4,7 +4,6 @@ // console.error, empty object returned) so the extension always starts. import type { SettingSource } from "@anthropic-ai/claude-agent-sdk"; -import type { ContextWindowMode } from "./models.js"; import { CONFIG_DIR_NAME } from "@oh-my-pi/pi-utils"; import { existsSync, readFileSync } from "fs"; import { homedir } from "os"; @@ -27,15 +26,6 @@ export interface Config { settingSources?: SettingSource[]; strictMcpConfig?: boolean; pathToClaudeCodeExecutable?: string; - // Subscription plan tier. Setting to "max" enables Opus 4.6 at 1M context - plan?: "pro" | "max"; - // Set to true to opt into metered 1M context usage ("extra usage" in - // Anthropic billing). Enables Sonnet 4.6 [1m] on every plan and Opus 4.6 - // [1m] on Pro. - longContextExtraUsage?: boolean; - // Force the Claude Code context window for every model: - // "auto" (default) - per-model policy, "1m" - force 1M, "200k" - force 200K. - contextWindow?: ContextWindowMode; }; } diff --git a/src/index.ts b/src/index.ts index 77e3b7f..499881b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,7 +13,7 @@ import { appendFileSync, mkdirSync, realpathSync, statSync } from "fs"; import { homedir } from "os"; import { dirname, join } from "path"; import { PROVIDER_ID, messageContentToText, convertPiMessages } from "./convert.js"; -import { buildVariantModels, buildModels, claudeCodeModelId, type ContextWindowMode, type LongContextSettings, resolveModel as _resolveModel } from "./models.js"; +import { buildModels, resolveModel as _resolveModel } from "./models.js"; import { MCP_SERVER_NAME, MCP_TOOL_PREFIX, extractSkillsBlock } from "./skills.js"; import { verifyWrittenSession as _verifyWrittenSession } from "./session-verify.js"; import { extractAllToolResults as _extractAllToolResults, type McpResult } from "./extract-tool-results.js"; @@ -22,6 +22,7 @@ import { loadConfig, type Config } from "./config.js"; import { extractAgentsAppend } from "./agents-md.js"; import { jsonSchemaToZodShape } from "./typebox-to-zod.js"; import { buildActionSummary, type ToolCallState } from "./askclaude-ui.js"; +import { registerClaudeProvider, releaseClaudeProviderStream } from "./provider-registration.js"; import { rateLimitNotice } from "./rate-limit.js"; // Compat (#2): use factory if available (pi-ai ≥0.66), else fall back to constructor (gsd-pi etc.) @@ -107,21 +108,6 @@ function diagDump(label: string, data: Record) { // --- Constants --- -// Global key to prevent re-registration of the provider across module reloads. -// -// Extensions like OMP subagents spawn a subagent and it loads this module -// again. Without this guard, the subagent's call to registerProvider() would -// overwrite the parent's `streamSimple` function reference in the shared -// ModelRegistry. When the parent later delivers a tool result, it would call -// the subagent's `streamSimple` (which has empty state) instead of its own. -// -// By storing the active streamSimple in a Symbol.for() global (shared across all -// module instances), we ensure only the FIRST instance to register takes effect. -// Subsequent instances wrap the stored function instead of overwriting it. -// -// On session_shutdown (including /reload), clearSession() resets this so a fresh -// registration can occur for the next session. -const ACTIVE_STREAM_SIMPLE_KEY = Symbol.for("claude-bridge:activeStreamSimple"); const SDK_TO_PI_TOOL_NAME: Record = { read: "read", write: "write", edit: "edit", bash: "bash", @@ -130,7 +116,6 @@ const SDK_TO_PI_TOOL_NAME: Record = { // MODELS is buildModels(getModels("anthropic")) — projection kept in models.js. const MODELS = buildModels(getModels("anthropic")); let providerSettings: NonNullable = {}; -let longContextSettings: LongContextSettings = { plan: "pro", longContextExtraUsage: false, contextWindow: "auto" }; function resolveModel(input: string) { return _resolveModel(MODELS, input); @@ -364,21 +349,19 @@ async function runIsolatedSummary( const promptText = extractIsolatedSummaryPrompt(context.messages); const cwd = (options as { cwd?: string } | undefined)?.cwd ?? process.cwd(); const claudeExecutable = loadConfig(cwd).provider?.pathToClaudeCodeExecutable; - const cliModel = claudeCodeModelId(model, longContextSettings); - debug(`compact summary: spawn model=${cliModel} registeredModel=${model.id} promptLen=${promptText.length}`); + debug(`compact summary: spawn model=${model.id} promptLen=${promptText.length}`); sdkQuery = query({ prompt: promptText, options: { cwd, - env: { ...process.env, DISABLE_AUTO_COMPACT: "1", CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1" }, tools: [], strictMcpConfig: true, settingSources: [] as SettingSource[], skills: [], persistSession: false, systemPrompt: context.systemPrompt, - model: cliModel, + model: model.id, maxTurns: 1, ...(claudeExecutable ? { pathToClaudeCodeExecutable: claudeExecutable } : {}), ...makeCliDebugOptions("compact-summary"), @@ -1235,37 +1218,21 @@ function streamClaudeAgentSdk(model: Model, context: Context, options?: Sim const strictMcpConfigEnabled = providerSettings.strictMcpConfig !== false; const claudeExecutable = providerSettings.pathToClaudeCodeExecutable; - // Prefer the model's own thinkingLevelMap when present (pi-ai 0.72+ ships - // per-model overrides — e.g. opus-4-7 wants xhigh→xhigh, not xhigh→max). - // Fall back to our generic table for older pi-ai or unmapped levels. + // Prefer OMP's canonical per-model effort mapping, then fall back to the + // bridge's generic Claude Code mapping for an unmapped reasoning level. const effort = options?.reasoning - ? ((model as any).thinkingLevelMap?.[options.reasoning] as EffortLevel | undefined) + ? (model.thinking?.effortMap?.[options.reasoning] as EffortLevel | undefined) ?? REASONING_TO_EFFORT[options.reasoning] : undefined; - // cliModel is the actual id sent to Claude Code (may carry [1m]); model.id is the - // pi-registered id. Log cliModel so debug lines reflect what CC actually received. - const cliModel = claudeCodeModelId(model, longContextSettings); - const extraArgs: Record = { model: cliModel }; + const extraArgs: Record = { model: model.id }; if (strictMcpConfigEnabled) extraArgs["strict-mcp-config"] = null; // Opus 4.7 defaults thinking.display to "omitted" (empty thinking text in stream). // Force summarized so thinking_delta events arrive. See anthropics/claude-agent-sdk-python#830. if (effort) extraArgs["thinking-display"] = "summarized"; - // Suppress claude.ai cloud MCP servers (Figma/Canva/etc. auto-discovered via OAuth - // when the user is logged into Anthropic). These are a separate code path from - // filesystem MCP and are NOT blocked by --strict-mcp-config or settingSources=undefined. - // The native CC binary gates them on env var ENABLE_CLAUDEAI_MCP_SERVERS: setting it - // to "0"/"false"/"no"/"off" makes the loader return early before any cloud fetch. - // DISABLE_AUTO_COMPACT=1: pi owns context-management and propagates its own - // /compact via session_compact (see handler in default export). Letting CC - // also autocompact would double-flush the prompt cache and races pi's - // threshold with CC's, including CC's anti-thrashing guard (issue #8). - // Manual /compact in CC still works (we never invoke it). - const childEnv = { ...process.env, ENABLE_CLAUDEAI_MCP_SERVERS: "0", DISABLE_AUTO_COMPACT: "1" }; const queryOptions: NonNullable[0]["options"]> = { cwd, - env: childEnv, tools: [], permissionMode: "bypassPermissions", includePartialMessages: true, @@ -1283,7 +1250,7 @@ function streamClaudeAgentSdk(model: Model, context: Context, options?: Sim }; debug("provider: fresh query", - `model=${cliModel} msgs=${context.messages.length} tools=${mcpTools.length}`, + `model=${model.id} msgs=${context.messages.length} tools=${mcpTools.length}`, `resume=${resumeSessionId?.slice(0, 8) ?? "none"} effort=${effort ?? "default"}`, `appendSys=${appendSystemPrompt} strictMcp=${strictMcpConfigEnabled}`, `prompt=${promptText.slice(0, 60)}${promptBlocks ? " [+images]" : ""}`); @@ -1370,7 +1337,7 @@ function streamClaudeAgentSdk(model: Model, context: Context, options?: Sim const contQuery = query({ prompt: steerPrompt, options: contOptions }); queryCtx.activeQuery = contQuery; - debug(`provider: continuation query, model=${cliModel}, resume=${resumeId.slice(0, 8)}, prompt=${steerPrompt.slice(0, 60)}`); + debug(`provider: continuation query, model=${model.id}, resume=${resumeId.slice(0, 8)}, prompt=${steerPrompt.slice(0, 60)}`); try { const { capturedSessionId: contSid } = await consumeQuery(contQuery, customToolNameToPi, model, () => wasAborted, queryCtx); @@ -1396,7 +1363,7 @@ function streamClaudeAgentSdk(model: Model, context: Context, options?: Sim finalizeCurrentStream(queryCtx, queryCtx.turnOutput?.stopReason); }) .catch((error) => { - debug(`provider: query error, model=${cliModel}, aborted=${Boolean(options?.signal?.aborted)}, error=`, error); + debug(`provider: query error, model=${model.id}, aborted=${Boolean(options?.signal?.aborted)}, error=`, error); if ((wasAborted || options?.signal?.aborted) && sharedSession) { sharedSession = { ...sharedSession, needsRebuild: true, forceRotate: true }; } else { @@ -1455,9 +1422,7 @@ async function promptAndWait( ): Promise<{ responseText: string; stopReason: string }> { const cwd = process.cwd(); const requestedModel = options?.model ?? "opus"; - const model = resolveModel(requestedModel); - const modelId = model?.id ?? requestedModel; - const cliModel = model ? claudeCodeModelId(model, longContextSettings) : modelId; + const modelId = resolveModel(requestedModel)?.id ?? requestedModel; // Session resume for shared mode — reuse provider's session if it exists, // otherwise create one from pi's context. @@ -1492,12 +1457,12 @@ async function promptAndWait( const extraArgs: Record = { "strict-mcp-config": null, - model: cliModel, + model: modelId, }; if (effort) extraArgs["thinking-display"] = "summarized"; debug("askClaude:", - `mode=${mode} model=${modelId} cliModel=${cliModel} effort=${effort ?? "default"}`, + `mode=${mode} model=${modelId} effort=${effort ?? "default"}`, `isolated=${options?.isolated ?? false} resume=${resumeSessionId?.slice(0, 8) ?? "none"}`, `skills=${Boolean(skillsBlock)} promptLen=${prompt.length}`); @@ -1505,7 +1470,6 @@ async function promptAndWait( prompt, options: { cwd, - env: { ...process.env, ENABLE_CLAUDEAI_MCP_SERVERS: "0", DISABLE_AUTO_COMPACT: "1" }, permissionMode: "bypassPermissions", ...(disallowedTools.length ? { disallowedTools } : {}), ...(effort ? { effort } : {}), @@ -1609,48 +1573,34 @@ const PREVIEW_MAX_LINES = 6; let askClaudeToolName = "AskClaude"; export default function (pi: ExtensionAPI) { - // Disable non-essential Claude Code traffic (update checks, MCP registry, telemetry) + // Keep OMP in sole control of compaction and prevent Claude.ai cloud MCP + // auto-discovery. Set only non-credential controls in the inherited parent + // environment; query() receives no env object or authentication material. process.env.CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC = "1"; + process.env.DISABLE_AUTO_COMPACT = "1"; + process.env.ENABLE_CLAUDEAI_MCP_SERVERS = "0"; const config = loadConfig(process.cwd()); debug("loadConfig:", JSON.stringify(config)); providerSettings = config.provider ?? {}; - const contextWindowSetting = providerSettings.contextWindow; - const contextWindow: ContextWindowMode = - contextWindowSetting === "auto" || contextWindowSetting === "1m" || contextWindowSetting === "200k" - ? contextWindowSetting - : "auto"; - if (contextWindowSetting != null && contextWindow !== contextWindowSetting) { - console.error(`claude-bridge: invalid provider.contextWindow "${String(contextWindowSetting)}", using auto`); - } - longContextSettings = { - plan: providerSettings.plan ?? "pro", - longContextExtraUsage: providerSettings.longContextExtraUsage ?? false, - contextWindow, - }; - const registeredModels = buildVariantModels(MODELS, longContextSettings); + const registeredModels = MODELS; - // Reset shared session on pi session lifecycle events - const clearSession = (event: string) => { + // Session changes reset conversation state without disturbing the provider + // stream owner shared by parent and subagent extension instances. + const resetSharedSession = (event: string) => { debug(`${event}: clearing session ${sharedSession?.sessionId?.slice(0, 8) ?? "none"}`); sharedSession = null; - - // Clear the global streamSimple if this instance registered it. - // This allows /reload to work — the old instance clears the flag so - // the new instance can register fresh without wrapping stale state. - const g = globalThis as Record; - if (g[ACTIVE_STREAM_SIMPLE_KEY] === streamClaudeAgentSdk) { - debug(`${event}: clearing ACTIVE_STREAM_SIMPLE_KEY`); - g[ACTIVE_STREAM_SIMPLE_KEY] = undefined; - } }; pi.on("session_start", (_event, ctx) => { piUI = ctx.ui; - clearSession("session_start"); + resetSharedSession("session_start"); + }); + pi.on("session_switch", (event) => resetSharedSession(`session_switch:${event.reason}`)); + pi.on("session_branch", () => resetSharedSession("session_branch")); + pi.on("session_shutdown", () => { + resetSharedSession("session_shutdown"); + releaseClaudeProviderStream(streamClaudeAgentSdk); }); - pi.on("session_switch", (event) => clearSession(`session_switch:${event.reason}`)); - pi.on("session_branch", () => clearSession("session_branch")); - pi.on("session_shutdown", () => clearSession("session_shutdown")); pi.on("session_before_compact", async (event, ctx) => { if (ctx.model?.baseUrl !== "claude-bridge") return undefined; @@ -1697,32 +1647,11 @@ export default function (pi: ExtensionAPI) { pi.on("session_compact", (event) => markRebuild(`session_compact:fromExtension=${event.fromExtension}`)); pi.on("session_tree", () => markRebuild("session_tree")); - // --- Provider --- - // - // Guard against re-registration when the module is loaded multiple times - // (e.g., when spawning subagents). The shared ModelRegistry would otherwise - // overwrite the parent's streamSimple, breaking tool result delivery. - // See ACTIVE_STREAM_SIMPLE_KEY for the full mechanism. - - const g = globalThis as Record; - if (!g[ACTIVE_STREAM_SIMPLE_KEY]) { - // First instance: store our streamSimple and register. - g[ACTIVE_STREAM_SIMPLE_KEY] = streamClaudeAgentSdk; - pi.registerProvider(PROVIDER_ID, { - baseUrl: "claude-bridge", - apiKey: "not-used", - api: "claude-bridge", - models: registeredModels, - // Cast: pi-ai AssistantMessageEventStream diamond dep between pi-coding-agent and pi-agent-core - streamSimple: streamClaudeAgentSdk as any, - }); - } else { - // Subsequent instance (subagent session): skip registration entirely. - // The subagent already has access to claude-bridge models via the shared - // ModelRegistry from the parent's registration. Calls to those models - // route through the parent's streamSimple via reentrant QueryContexts. - debug(`provider: skipping re-registration, parent instance active (module=${moduleInstanceId})`); - } + // Every extension load must queue a registration because OMP clears prior + // registrations from this extension source before applying the new load. + // The helper preserves the first stream function so subagent loads cannot + // replace the parent session's stateful provider implementation. + registerClaudeProvider(pi, registeredModels, streamClaudeAgentSdk); // --- AskClaude tool --- diff --git a/src/models.ts b/src/models.ts index 3eff3e3..38dd88a 100644 --- a/src/models.ts +++ b/src/models.ts @@ -1,228 +1,36 @@ +import type { ProviderModelConfig } from "@oh-my-pi/pi-coding-agent"; + // Canonical selection + display order for the model picker. // `resolveModel` returns the first partial match, so `opus` resolves to the first-listed opus entry. // Extracted from index.ts so tests can import without activating the extension. export const MODEL_IDS_IN_ORDER = ["claude-fable-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-5", "claude-sonnet-4-6", "claude-haiku-4-5"]; -// Workaround for models that ship without a thinkingLevelMap. Sonnet 5 and -// Sonnet 4.6 have no map, so getSupportedThinkingLevels hides xhigh (it's -// opt-in). Both models' top effort tier is "max" with no real xhigh (verified -// via Claude Code's supportedModels API), so xhigh->max matches opus-4-6. -const DEFAULT_THINKING_LEVEL_MAPS: Record> = { - "claude-sonnet-5": { xhigh: "max" }, - "claude-sonnet-4-6": { xhigh: "max" }, -}; - -// Project pi-ai's model entries down to the fields OMP's registerProvider expects, -// and keep MODEL_IDS_IN_ORDER ordering. IDs missing from pi-ai are silently dropped. -// Context-dependent display labels are applied after plan/long-context config is known. -export function buildModels(piAiModels: T[]) { - return MODEL_IDS_IN_ORDER - .map((id) => piAiModels.find((m) => m.id === id)) - .filter((m) => m != null) - // Forward thinkingLevelMap so per-model overrides (e.g. opus-4-7 mapping - // xhigh->xhigh instead of xhigh->max) are visible to the effort lookup. - .map(({ id, name, reasoning, input, contextWindow, maxTokens, thinkingLevelMap }) => ({ - id, - name, - reasoning, input, contextWindow, maxTokens, - thinkingLevelMap: thinkingLevelMap ?? DEFAULT_THINKING_LEVEL_MAPS[id], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - })); -} - -// User-selectable context-window policy (see provider.contextWindow in config). -// "auto" - per-model default policy (measured SDK behavior). -// "1m" - force 1M: only register 1M-capable models, request [1m] where needed. -// "200k" - force 200K: only register 200K-capable models, request bare model ids. -export type ContextWindowMode = "auto" | "1m" | "200k"; - -export type LongContextSettings = { - plan: "pro" | "max"; - longContextExtraUsage: boolean; - contextWindow: ContextWindowMode; -}; - -export type ClaudeCodeRuntimeModel = { - cliModelId: string; - contextWindow: number; -}; - -const TWO_HUNDRED_K_CONTEXT = 200_000; -const ONE_M_CONTEXT = 1_000_000; - -// Measured Claude Agent SDK subscription/OAuth behavior. Do not infer this from -// pi-ai's advertised contextWindow: bare Opus 4.7 serves 1M, bare Opus 4.8 does -// not, bare Fable 5 serves 200K while claude-fable-5[1m] serves 1M, and [1m] -// entitlement differs by model. Returns null when a model has no runtime for the -// requested forced window (that model is hidden from the picker in that mode). -export function resolveClaudeCodeRuntimeModel(modelId: string, settings: LongContextSettings): ClaudeCodeRuntimeModel | null { - switch (settings.contextWindow) { - case "1m": - return resolveForcedOneMRuntimeModel(modelId); - case "200k": - return resolveForcedTwoHundredKRuntimeModel(modelId); - case "auto": - return resolveAutoRuntimeModel(modelId, settings); - } -} - -function resolveAutoRuntimeModel(modelId: string, settings: LongContextSettings): ClaudeCodeRuntimeModel { - switch (modelId) { - case "claude-opus-4-8": - return { cliModelId: "claude-opus-4-8[1m]", contextWindow: ONE_M_CONTEXT }; - case "claude-opus-4-7": - return { cliModelId: "claude-opus-4-7", contextWindow: ONE_M_CONTEXT }; - case "claude-opus-4-6": { - const useOneM = settings.plan === "max" || settings.longContextExtraUsage; - return { - cliModelId: useOneM ? "claude-opus-4-6[1m]" : "claude-opus-4-6", - contextWindow: useOneM ? ONE_M_CONTEXT : TWO_HUNDRED_K_CONTEXT, - }; - } - case "claude-fable-5": - return { cliModelId: "claude-fable-5", contextWindow: TWO_HUNDRED_K_CONTEXT }; - case "claude-sonnet-5": - return { cliModelId: "claude-sonnet-5[1m]", contextWindow: ONE_M_CONTEXT }; - case "claude-sonnet-4-6": - return { - cliModelId: settings.longContextExtraUsage ? "claude-sonnet-4-6[1m]" : "claude-sonnet-4-6", - contextWindow: settings.longContextExtraUsage ? ONE_M_CONTEXT : TWO_HUNDRED_K_CONTEXT, - }; - case "claude-haiku-4-5": - return { cliModelId: "claude-haiku-4-5", contextWindow: TWO_HUNDRED_K_CONTEXT }; - default: - console.error(`claude-bridge: encountered model ${modelId} with no known context size, defaulting to 200K`); - return { cliModelId: modelId, contextWindow: TWO_HUNDRED_K_CONTEXT }; - } -} - -function resolveForcedOneMRuntimeModel(modelId: string): ClaudeCodeRuntimeModel | null { - switch (modelId) { - case "claude-opus-4-8": - return { cliModelId: "claude-opus-4-8[1m]", contextWindow: ONE_M_CONTEXT }; - case "claude-opus-4-7": - return { cliModelId: "claude-opus-4-7", contextWindow: ONE_M_CONTEXT }; - case "claude-opus-4-6": - return { cliModelId: "claude-opus-4-6[1m]", contextWindow: ONE_M_CONTEXT }; - case "claude-fable-5": - return { cliModelId: "claude-fable-5[1m]", contextWindow: ONE_M_CONTEXT }; - case "claude-sonnet-5": - return { cliModelId: "claude-sonnet-5[1m]", contextWindow: ONE_M_CONTEXT }; - case "claude-sonnet-4-6": - return { cliModelId: "claude-sonnet-4-6[1m]", contextWindow: ONE_M_CONTEXT }; - case "claude-haiku-4-5": - return null; - default: - console.error(`claude-bridge: encountered model ${modelId} with no known 1M runtime, hiding it`); - return null; - } -} - -function resolveForcedTwoHundredKRuntimeModel(modelId: string): ClaudeCodeRuntimeModel | null { - switch (modelId) { - case "claude-opus-4-8": - return { cliModelId: "claude-opus-4-8", contextWindow: TWO_HUNDRED_K_CONTEXT }; - case "claude-opus-4-7": - return null; - case "claude-opus-4-6": - return { cliModelId: "claude-opus-4-6", contextWindow: TWO_HUNDRED_K_CONTEXT }; - case "claude-fable-5": - return { cliModelId: "claude-fable-5", contextWindow: TWO_HUNDRED_K_CONTEXT }; - case "claude-sonnet-5": - return { cliModelId: "claude-sonnet-5", contextWindow: TWO_HUNDRED_K_CONTEXT }; - case "claude-sonnet-4-6": - return { cliModelId: "claude-sonnet-4-6", contextWindow: TWO_HUNDRED_K_CONTEXT }; - case "claude-haiku-4-5": - return { cliModelId: "claude-haiku-4-5", contextWindow: TWO_HUNDRED_K_CONTEXT }; - default: - console.error(`claude-bridge: encountered model ${modelId} with no known 200K runtime, hiding it`); - return null; - } -} - -// Split a registered picker id into its base model id and the forced window it -// encodes. Variant ids carry a "-1m"/"-200k" suffix (see buildVariantModels); the -// unsuffixed id maps to the config default. Base ids never end in those suffixes, -// so the split is unambiguous. -export function parseVariantId(id: string): { baseId: string; forced?: "1m" | "200k" } { - if (id.endsWith("-1m")) return { baseId: id.slice(0, -3), forced: "1m" }; - if (id.endsWith("-200k")) return { baseId: id.slice(0, -5), forced: "200k" }; - return { baseId: id }; -} - -export function claudeCodeModelId(model: { id: string }, settings: LongContextSettings): string { - const { baseId, forced } = parseVariantId(model.id); - const runtimeModel = forced === "1m" - ? resolveForcedOneMRuntimeModel(baseId) - : forced === "200k" - ? resolveForcedTwoHundredKRuntimeModel(baseId) - : resolveClaudeCodeRuntimeModel(baseId, settings); - if (runtimeModel == null) { - const requested = forced ?? settings.contextWindow; - throw new Error(`claude-bridge: model ${model.id} has no Claude Code runtime (contextWindow=${requested})`); - } - return runtimeModel.cliModelId; +// Select the canonical OMP catalog entries in a stable picker order. Copy only +// provider-model metadata: source routing fields such as `api`, `provider`, and +// `baseUrl` must not override the bridge's custom stream handler. +export function buildModels(ompModels: T[]): ProviderModelConfig[] { + const modelsById = new Map(ompModels.map((model) => [model.id, model])); + return MODEL_IDS_IN_ORDER.flatMap((id) => { + const model = modelsById.get(id); + if (!model) return []; + return [{ + id: model.id, + name: model.name, + reasoning: model.reasoning, + ...(model.thinking ? { thinking: model.thinking } : {}), + input: model.input, + cost: model.cost, + ...(model.premiumMultiplier != null ? { premiumMultiplier: model.premiumMultiplier } : {}), + contextWindow: model.contextWindow, + maxTokens: model.maxTokens, + ...(model.headers ? { headers: model.headers } : {}), + ...(model.compat ? { compat: model.compat } : {}), + }]; + }); } export function resolveModel(models: T[], input: string): T | undefined { const lower = input.toLowerCase(); return models.find((m) => m.id === lower || m.id.includes(lower)); } - -function variantName(baseName: string, contextWindow: number): string { - const label = contextWindow === ONE_M_CONTEXT ? "1M" : "200K"; - // Strip any window hint pi-ai already baked into the name so we don't double it. - const base = baseName.replace(/\s*(?:\((?:1M|200K)\)|\b1M\b)\s*$/i, "").trimEnd(); - return `${base} (${label})`; -} - -// Expand each model into one registered entry per context window it supports, so -// the user picks the window on demand from OMP's model picker. The unsuffixed id -// (e.g. claude-opus-4-8) maps to the config default window; every other available -// window gets a "-1m"/"-200k" suffixed id. Each entry's contextWindow must match -// the window the bridge actually requests (see claudeCodeModelId), or OMP's status -// bar and auto-compaction threshold will misreport. Both windows stay pickable -// regardless of provider.contextWindow, which only picks the default. -export function buildVariantModels( - models: T[], - settings: LongContextSettings, -): T[] { - const result: T[] = []; - for (const m of models) { - // Unknown model (not in the model tables): keep one default-path entry. - // Done before the forced-resolver probes below, which log "hiding it" on - // unknown ids — misleading noise for a model we actually keep. - if (!MODEL_IDS_IN_ORDER.includes(m.id)) { - const runtimeModel = resolveClaudeCodeRuntimeModel(m.id, settings); - if (runtimeModel != null) result.push({ ...m, contextWindow: runtimeModel.contextWindow, name: variantName(m.name, runtimeModel.contextWindow) }); - continue; - } - - // Known models always have at least one available window. - const available: Array<{ kind: "1m" | "200k"; contextWindow: number }> = []; - if (resolveForcedOneMRuntimeModel(m.id) != null) available.push({ kind: "1m", contextWindow: ONE_M_CONTEXT }); - if (resolveForcedTwoHundredKRuntimeModel(m.id) != null) available.push({ kind: "200k", contextWindow: TWO_HUNDRED_K_CONTEXT }); - - // The config default decides which window is unsuffixed; fall back to the sole - // available window when the preferred one has no runtime (e.g. Haiku under - // "1m", Opus 4.7 under "200k"). - const defaultRuntime = resolveClaudeCodeRuntimeModel(m.id, settings); - const preferredKind: "1m" | "200k" | undefined = defaultRuntime == null - ? undefined - : defaultRuntime.contextWindow === ONE_M_CONTEXT ? "1m" : "200k"; - const defaultKind = preferredKind != null && available.some((a) => a.kind === preferredKind) - ? preferredKind - : available[0].kind; - - const ordered = [ - ...available.filter((a) => a.kind === defaultKind), - ...available.filter((a) => a.kind !== defaultKind), - ]; - for (const { kind, contextWindow } of ordered) { - const id = kind === defaultKind ? m.id : `${m.id}-${kind}`; - result.push({ ...m, id, contextWindow, name: variantName(m.name, contextWindow) }); - } - } - return result; -} diff --git a/src/provider-registration.ts b/src/provider-registration.ts new file mode 100644 index 0000000..165e92c --- /dev/null +++ b/src/provider-registration.ts @@ -0,0 +1,31 @@ +import type { ExtensionAPI, ProviderConfig } from "@oh-my-pi/pi-coding-agent"; + +const ACTIVE_STREAM_SIMPLE_KEY = Symbol.for("claude-bridge:activeStreamSimple"); + +type StreamSimple = NonNullable; +type ProviderRegistrar = Pick; + +export function registerClaudeProvider( + pi: ProviderRegistrar, + models: NonNullable, + candidateStream: StreamSimple, +): void { + const globalState = globalThis as Record; + const activeStream = globalState[ACTIVE_STREAM_SIMPLE_KEY] ?? candidateStream; + globalState[ACTIVE_STREAM_SIMPLE_KEY] = activeStream; + + pi.registerProvider("claude-bridge", { + baseUrl: "claude-bridge", + apiKey: "not-used", + api: "claude-bridge", + models, + streamSimple: activeStream, + }); +} + +export function releaseClaudeProviderStream(candidateStream: StreamSimple): void { + const globalState = globalThis as Record; + if (globalState[ACTIVE_STREAM_SIMPLE_KEY] === candidateStream) { + delete globalState[ACTIVE_STREAM_SIMPLE_KEY]; + } +} diff --git a/tests/unit-context-window.mjs b/tests/unit-context-window.mjs deleted file mode 100644 index 8bbf7b9..0000000 --- a/tests/unit-context-window.mjs +++ /dev/null @@ -1,119 +0,0 @@ -import test from "node:test"; -import assert from "node:assert/strict"; - -import { buildVariantModels, claudeCodeModelId, parseVariantId } from "../src/models.ts"; - -// Minimal stand-ins for pi-ai model entries (buildVariantModels reads id, name, -// contextWindow and spreads the rest through to each variant). -const MODELS = [ - { id: "claude-fable-5", name: "Fable 5", contextWindow: 1_000_000 }, - { id: "claude-opus-4-8", name: "Opus 4.8", contextWindow: 200_000 }, - { id: "claude-opus-4-7", name: "Opus 4.7", contextWindow: 1_000_000 }, - { id: "claude-opus-4-6", name: "Opus 4.6", contextWindow: 200_000 }, - { id: "claude-sonnet-5", name: "Sonnet 5", contextWindow: 200_000 }, - { id: "claude-sonnet-4-6", name: "Sonnet 4.6", contextWindow: 200_000 }, - { id: "claude-haiku-4-5", name: "Haiku 4.5", contextWindow: 200_000 }, -]; - -const settings = (contextWindow, extra = {}) => ({ plan: "pro", longContextExtraUsage: false, contextWindow, ...extra }); -const variants = (contextWindow, extra) => buildVariantModels(MODELS, settings(contextWindow, extra)); -const byId = (contextWindow, extra) => Object.fromEntries(variants(contextWindow, extra).map((m) => [m.id, m])); - -test("auto (Pro): each model expands to its available windows with correct ids, windows, and labels", () => { - const m = byId("auto"); - // Opus 4.8: default 1M unsuffixed + 200K alternate. - assert.equal(m["claude-opus-4-8"].contextWindow, 1_000_000); - assert.equal(m["claude-opus-4-8"].name, "Opus 4.8 (1M)"); - assert.equal(m["claude-opus-4-8-200k"].contextWindow, 200_000); - assert.equal(m["claude-opus-4-8-200k"].name, "Opus 4.8 (200K)"); - // Opus 4.7: 1M only, no 200K variant. - assert.equal(m["claude-opus-4-7"].contextWindow, 1_000_000); - assert.ok(!m["claude-opus-4-7-200k"], "opus-4-7 has no 200K runtime"); - // Opus 4.6 (Pro): default 200K unsuffixed + 1M alternate. - assert.equal(m["claude-opus-4-6"].contextWindow, 200_000); - assert.equal(m["claude-opus-4-6-1m"].contextWindow, 1_000_000); - // Fable 5: default 200K + 1M alternate. - assert.equal(m["claude-fable-5"].contextWindow, 200_000); - assert.equal(m["claude-fable-5-1m"].contextWindow, 1_000_000); - // Sonnet 5: default 1M + 200K alternate. - assert.equal(m["claude-sonnet-5"].contextWindow, 1_000_000); - assert.equal(m["claude-sonnet-5-200k"].contextWindow, 200_000); - // Sonnet 4.6: default 200K + 1M alternate. - assert.equal(m["claude-sonnet-4-6"].contextWindow, 200_000); - assert.equal(m["claude-sonnet-4-6-1m"].contextWindow, 1_000_000); - // Haiku 4.5: 200K only, no 1M variant. - assert.equal(m["claude-haiku-4-5"].contextWindow, 200_000); - assert.ok(!m["claude-haiku-4-5-1m"], "haiku has no 1M runtime"); -}); - -test("auto (Pro): 12 entries, and no base model emits two entries for the same window", () => { - const list = variants("auto"); - assert.equal(list.length, 12); - for (const base of MODELS.map((mm) => mm.id)) { - const windows = list.filter((v) => v.id === base || v.id.startsWith(`${base}-`)).map((v) => v.contextWindow); - assert.equal(new Set(windows).size, windows.length, `${base} has duplicate windows`); - } -}); - -test("the default variant is listed before its suffixed alternate", () => { - const ids = variants("auto").map((m) => m.id); - assert.ok(ids.indexOf("claude-opus-4-8") < ids.indexOf("claude-opus-4-8-200k")); - assert.ok(ids.indexOf("claude-sonnet-5") < ids.indexOf("claude-sonnet-5-200k")); - assert.ok(ids.indexOf("claude-fable-5") < ids.indexOf("claude-fable-5-1m")); -}); - -test("auto (Max): Opus 4.6 default flips to 1M and 200K becomes the suffixed alternate", () => { - const m = byId("auto", { plan: "max" }); - assert.equal(m["claude-opus-4-6"].contextWindow, 1_000_000); - assert.equal(m["claude-opus-4-6-200k"].contextWindow, 200_000); - assert.ok(!m["claude-opus-4-6-1m"], "1M is the default (unsuffixed) under Max"); -}); - -test("200k config: unsuffixed prefers 200K, 1M stays available as -1m, Opus 4.7 falls back to 1M", () => { - const m = byId("200k"); - assert.equal(m["claude-opus-4-8"].contextWindow, 200_000); - assert.equal(m["claude-opus-4-8-1m"].contextWindow, 1_000_000); - assert.ok(!m["claude-opus-4-8-200k"], "200K is the default here, so no suffixed duplicate"); - // Opus 4.7 has no 200K runtime, so its only window (1M) becomes the unsuffixed default. - assert.equal(m["claude-opus-4-7"].contextWindow, 1_000_000); - assert.ok(!m["claude-opus-4-7-1m"]); - assert.equal(m["claude-haiku-4-5"].contextWindow, 200_000); -}); - -test("1m config: unsuffixed prefers 1M, 200K stays available as -200k, Haiku falls back to 200K", () => { - const m = byId("1m"); - assert.equal(m["claude-opus-4-8"].contextWindow, 1_000_000); - assert.equal(m["claude-opus-4-8-200k"].contextWindow, 200_000); - assert.ok(!m["claude-opus-4-8-1m"], "1M is the default here, so no suffixed duplicate"); - // Haiku has no 1M runtime, so 200K stays the unsuffixed default. - assert.equal(m["claude-haiku-4-5"].contextWindow, 200_000); - assert.ok(!m["claude-haiku-4-5-200k"]); - assert.equal(m["claude-opus-4-7"].contextWindow, 1_000_000); -}); - -test("parseVariantId splits window suffixes and leaves base ids intact", () => { - assert.deepEqual(parseVariantId("claude-opus-4-8"), { baseId: "claude-opus-4-8" }); - assert.deepEqual(parseVariantId("claude-opus-4-8-200k"), { baseId: "claude-opus-4-8", forced: "200k" }); - assert.deepEqual(parseVariantId("claude-fable-5-1m"), { baseId: "claude-fable-5", forced: "1m" }); -}); - -test("claudeCodeModelId: unsuffixed id follows the config default", () => { - assert.equal(claudeCodeModelId({ id: "claude-fable-5" }, settings("auto")), "claude-fable-5"); - assert.equal(claudeCodeModelId({ id: "claude-fable-5" }, settings("1m")), "claude-fable-5[1m]"); - assert.equal(claudeCodeModelId({ id: "claude-opus-4-8" }, settings("auto")), "claude-opus-4-8[1m]"); - assert.equal(claudeCodeModelId({ id: "claude-opus-4-8" }, settings("200k")), "claude-opus-4-8"); -}); - -test("claudeCodeModelId: a suffixed id forces its window regardless of config", () => { - assert.equal(claudeCodeModelId({ id: "claude-opus-4-8-200k" }, settings("auto")), "claude-opus-4-8"); - assert.equal(claudeCodeModelId({ id: "claude-opus-4-8-200k" }, settings("1m")), "claude-opus-4-8"); - assert.equal(claudeCodeModelId({ id: "claude-fable-5-1m" }, settings("200k")), "claude-fable-5[1m]"); - assert.equal(claudeCodeModelId({ id: "claude-opus-4-6-1m" }, settings("auto")), "claude-opus-4-6[1m]"); -}); - -test("claudeCodeModelId throws when a model has no runtime for the requested window", () => { - assert.throws(() => claudeCodeModelId({ id: "claude-haiku-4-5-1m" }, settings("auto"))); - assert.throws(() => claudeCodeModelId({ id: "claude-opus-4-7-200k" }, settings("auto"))); - assert.throws(() => claudeCodeModelId({ id: "claude-haiku-4-5" }, settings("1m"))); - assert.throws(() => claudeCodeModelId({ id: "claude-opus-4-7" }, settings("200k"))); -}); diff --git a/tests/unit-models.mjs b/tests/unit-models.mjs new file mode 100644 index 0000000..0c984cc --- /dev/null +++ b/tests/unit-models.mjs @@ -0,0 +1,56 @@ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { MODEL_IDS_IN_ORDER, buildModels, resolveModel } from "../src/models.ts"; + +const catalog = [ + ...MODEL_IDS_IN_ORDER.map((id, index) => ({ + id, + name: `Catalog model ${index}`, + api: "anthropic-messages", + provider: "anthropic", + baseUrl: "https://api.anthropic.com", + reasoning: index % 2 === 0, + thinking: { mode: "anthropic-adaptive", efforts: ["low", "high"], effortMap: { low: "low", high: "max" } }, + input: index % 2 === 0 ? ["text", "image"] : ["text"], + cost: { input: index, output: index + 1, cacheRead: index + 2, cacheWrite: index + 3 }, + premiumMultiplier: index + 0.5, + contextWindow: 200_000 + index, + maxTokens: 32_000 + index, + headers: { "x-catalog-index": String(index) }, + compat: { supportsStore: index % 2 === 0 }, + })).reverse(), + { id: "unrelated-model", name: "Not registered" }, +]; + +test("buildModels returns one canonical entry per configured model in picker order", () => { + const models = buildModels(catalog); + + assert.deepEqual(models.map(({ id }) => id), MODEL_IDS_IN_ORDER); + assert.equal(new Set(models.map(({ id }) => id)).size, MODEL_IDS_IN_ORDER.length); +}); + +test("buildModels preserves provider metadata and omits source routing fields", () => { + const models = buildModels(catalog); + const expected = MODEL_IDS_IN_ORDER.map((id) => { + const { api: _api, provider: _provider, baseUrl: _baseUrl, ...metadata } = catalog.find((model) => model.id === id); + return metadata; + }); + + assert.deepEqual(models, expected); + assert.ok(models.every((model) => model.api == null && model.provider == null && model.baseUrl == null)); +}); + +test("buildModels omits canonical IDs missing from the catalog", () => { + const available = catalog.filter(({ id }) => id === MODEL_IDS_IN_ORDER[1] || id === MODEL_IDS_IN_ORDER[5]); + + assert.deepEqual(buildModels(available).map(({ id }) => id), [MODEL_IDS_IN_ORDER[1], MODEL_IDS_IN_ORDER[5]]); +}); + +test("resolveModel supports exact and ordered partial lookup", () => { + const models = buildModels(catalog); + + assert.equal(resolveModel(models, MODEL_IDS_IN_ORDER[5])?.id, MODEL_IDS_IN_ORDER[5]); + assert.equal(resolveModel(models, "OPUS")?.id, MODEL_IDS_IN_ORDER[1]); + assert.equal(resolveModel(models, "does-not-exist"), undefined); +}); diff --git a/tests/unit-provider-registration.mjs b/tests/unit-provider-registration.mjs new file mode 100644 index 0000000..1093ced --- /dev/null +++ b/tests/unit-provider-registration.mjs @@ -0,0 +1,37 @@ +import test from "node:test"; +import assert from "node:assert/strict"; + +import { registerClaudeProvider, releaseClaudeProviderStream } from "../src/provider-registration.ts"; + +test("every initialization queues registration while the first stream remains active", () => { + const registrations = []; + const pi = { + registerProvider(name, config) { + registrations.push({ name, config }); + }, + }; + const models = []; + const first = () => {}; + const second = () => {}; + const third = () => {}; + + registerClaudeProvider(pi, models, first); + registerClaudeProvider(pi, models, second); + + assert.equal(registrations.length, 2); + assert.deepEqual(registrations.map(({ name }) => name), ["claude-bridge", "claude-bridge"]); + assert.equal(registrations[0].config.streamSimple, first); + assert.equal(registrations[1].config.streamSimple, first); + assert.equal(registrations[0].config.models, models); + assert.equal(registrations[1].config.models, models); + + releaseClaudeProviderStream(second); + registerClaudeProvider(pi, models, third); + assert.equal(registrations[2].config.streamSimple, first); + + releaseClaudeProviderStream(first); + registerClaudeProvider(pi, models, third); + assert.equal(registrations[3].config.streamSimple, third); + + releaseClaudeProviderStream(third); +});