Compare commits

...

49 Commits

Author SHA1 Message Date
abeatrix 2f2be67c79 feat: SendSessionConnectionUpdate 2026-05-26 10:04:48 -07:00
Saoud Rizwan 8a6441fddd chore(cli): release v3.0.13 2026-05-22 17:41:54 -07:00
Saoud Rizwan 7ef5b1e7af test(llms): add provider VCR smoke tests to prevent e.g. ChatGPT regressions (#11012)
* test(llms): add provider vcr smoke tests

* fix(llms): harden provider vcr recording cleanup
2026-05-22 17:37:20 -07:00
Saoud Rizwan 3e58e7b024 fix(cli): show loading dialog for history resume (#11013) 2026-05-22 17:20:59 -07:00
Willis d16667f0b8 fix: use correct base URL for Vertex AI global endpoint with Claude models (#10288)
* fix: use correct base URL for Vertex AI global endpoint with Claude models

The AnthropicVertex SDK constructs the API hostname as
`${region}-aiplatform.googleapis.com`, which produces
`global-aiplatform.googleapis.com` when region is "global".
This hostname does not exist and returns 404.

Per Google Cloud docs, the correct global endpoint hostname is
`aiplatform.googleapis.com` (no region prefix). This fix overrides
the baseURL when region is "global" to use the correct hostname.

Fixes #10287

* chore: add changeset for vertex global endpoint fix

* fix: rebase on main and re-apply global endpoint baseURL override
2026-05-22 17:11:15 -07:00
Saoud Rizwan a740c49524 fix(cli): defer empty session creation after reset (#11000)
* fix(cli): skip empty clear session restart

* fix(cli): defer empty session creation after reset

* fix(cli): clarify session start race guard

* fix(cli): avoid re-resuming after new session reset
2026-05-22 17:02:47 -07:00
Saoud Rizwan 3bc1ee8382 feat(shared): add VCR request body contracts (#10997)
* feat(shared): add VCR request body contracts

* fix(shared): tighten VCR request body contracts

* test(shared): cover legacy VCR cassette playback
2026-05-22 16:00:36 -07:00
Saoud Rizwan ecf354c753 chore(cli): release v3.0.12 2026-05-22 15:14:29 -07:00
TheRealSpencer a66c5ee973 chore(deps): pin protobuf to 7.5.8 via overrides (#10998) 2026-05-22 15:11:06 -07:00
Saoud Rizwan 46659eebeb fix(cli): show loading dialog during model settings transitions (#10999)
* fix(cli): show loading dialog during model settings transitions

* docs(cli): explain loading dialog render yield
2026-05-22 14:54:16 -07:00
Saoud Rizwan 899ee0bfea fix(cli): add inline ask question tool prompt (#10989)
* fix(cli): inline runtime tool prompts

* fix(cli): address inline prompt review
2026-05-22 13:57:01 -07:00
Bee db4598e310 Cline SDK 0.0.42 (#10994)
Version bump
2026-05-22 13:31:48 -07:00
Saoud Rizwan 627e539266 fix(cli): bypass release age gate for manual updates (#10987)
* fix(cli): bypass release age gate for manual updates

* fix(cli): use yarn env override for update age gate
2026-05-22 13:29:25 -07:00
Saoud Rizwan 87ff61915f chore(cli): release v3.0.11 2026-05-22 13:03:25 -07:00
Saoud Rizwan a305556452 fix(llms): revert implicit output cap regression (#10990)
* fix(llms): avoid implicit output token caps

* test(llms): cover ChatGPT OAuth output token regression
2026-05-22 12:59:43 -07:00
Robin Newhouse ca12e97288 fix(cli): make config footer toggle hint contextual (#10976) 2026-05-22 12:34:48 -07:00
Bee 0c89716849 feat(core): includes tool names in tool results across messages (#10975)
* fix(llms): Use Google auth for Vertex Gemini

- Pass `providerConfig.gcp.projectId` through to Vertex Gemini as `googleAuthOptions.projectId`
- Disable Vertex API-key express mode when GCP project config is present so `google-auth-library` handles auth
- Add coverage for `AgentConfig.providerConfig.gcp` forwarding and Vertex Gemini provider creation
- Fix vertex model list only contains Claude models issue

* feat(core): includes tool names in tool results across messages

Updated `tool_result` content blocks to consistently include the `name` of the tool being executed. This change propagates through provider helpers and applies the new schema across all associated unit and live tests, ensuring proper tracking and logging of tool interactions within messages.
2026-05-22 11:36:32 -07:00
Robin Newhouse 1c401dbe1a Fix SDK LLM live provider configs (#10977) 2026-05-22 11:04:33 -07:00
Bee ed78404e4b fix(llms): Use Google auth for Vertex Gemini (#10974)
- Pass `providerConfig.gcp.projectId` through to Vertex Gemini as `googleAuthOptions.projectId`
- Disable Vertex API-key express mode when GCP project config is present so `google-auth-library` handles auth
- Add coverage for `AgentConfig.providerConfig.gcp` forwarding and Vertex Gemini provider creation
- Fix vertex model list only contains Claude models issue
2026-05-22 11:02:35 -07:00
Saoud Rizwan 0157ed9efb chore(cli): release v3.0.10 2026-05-21 20:23:07 -07:00
Saoud Rizwan 5574c95ff2 docs(cli): note ignore-scripts local pack guard quirk in publish-cli skill 2026-05-21 20:22:44 -07:00
Saoud Rizwan 31ee8eb744 feat(cli): install plugins from file URLs (#10945)
* feat(cli): install plugins from file URLs

* fix(cli): harden remote plugin installs

* docs: document plugin file URL installs

* docs: simplify plugin file URL wording

* docs: trim CLI plugin example
2026-05-21 19:58:20 -07:00
Renee Huang 7952e230ae Add Ollama API key note in TUI settings (#10947)
* Add Ollama API key note in TUI settings

* refactor: centralize provider config field metadata

---------

Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
2026-05-21 16:27:31 -07:00
Bee 6bcfa34ba9 feat(sdk): track idle and pending session states (#10959)
* feat(runtime): track idle and pending session states

Propagate idle and pending as non-terminal session statuses across the CLI, hub records, and active-session checks. Update runtime handling so interactive sessions remain active while idle or awaiting approval instead of being treated as ended.

Removed `status` from showing up in `cline history` for now.

* hydrate: false no longer reads message files for every session.
2026-05-21 16:09:45 -07:00
Ara cf18793434 feat(sdk): add Poolside provider (#10956) 2026-05-21 16:04:38 -07:00
Saoud Rizwan a7ba25d6e1 feat(uri): add /lg-task webhook integration for LG dashboard flow (#10194)
* feat(uri): add LG task deeplink webhook integration

* feat(uri): include prompt-file path in LG task prompt

* refactor(uri): move LG webhook setup into integration service
2026-05-21 16:03:21 -07:00
Ara 2af2028861 feat: add Gemini 3.5 Flash to Gemini providers (#10955) 2026-05-21 15:43:44 -07:00
Ara 932c8e68e1 Infer Telegram bot username from token (#10954)
* fix(cli): infer Telegram bot username from token

* fix(cli): address Telegram connector review feedback

* test(cli): confirm Telegram schedule delivery bot metadata

* fix(core): publish schedule completion events to connectors

* Revert "fix(core): publish schedule completion events to connectors"

This reverts commit 0d64f037b9.
2026-05-21 15:03:36 -07:00
Bee 3cd13352eb fix(cron): publish failed schedule execution events (#10937)
* fix(cron): publish failed schedule execution events

Add cron runner execution event publishing for completed and failed runs.
Update connector adapters to react to failed schedule executions so clients are notified when scheduled work does not complete successfully.

* add unit tests
2026-05-21 14:57:26 -07:00
Tomás Barreiro 2c842328a8 Inject OTEL variables into the cli at buildtime (#10958)
* Inject OTEL variables

* Add telemetry to the nightly

* Add variables to the build script
2026-05-21 23:43:30 +02:00
Saoud Rizwan d3b3ff1c33 fix(cli): satisfy config item hook lint (#10968) 2026-05-21 14:38:36 -07:00
Robin Newhouse 2508e76af8 Fix SDK model catalog token-limit semantics ENG-2100 (#10946)
* fix(llms): preserve catalog output limits

* chore(llms): regenerate model catalog
2026-05-21 14:19:35 -07:00
Ara a702bf9b38 fix(cli): soften rejected tool call display (#10871) 2026-05-21 14:00:55 -07:00
Robin Newhouse a8cea1dca3 Fix disabled skill availability in SDK CLI ENG-2058 (#10876)
* fix(sdk): hide skills tool when skills are disabled

* fix(cli): refresh skill slash commands after toggle
2026-05-21 11:23:14 -07:00
Bee 2a351ffdd5 fix: Bedrock legacy migration for awsProfile (#10943)
The new Bedrock path is not failing because credential_process is unsupported. Both old and new code use AWS SDK v3’s fromNodeProviderChain, which can load credential_process.

The practical difference is that the migrated config does not include the AWS profile name:

```
"aws": {
  "region": "us-east-1",
  "authentication": "profile"
}
```

There is no `"profile": "bedrock"` So the new llms provider never targets [profile bedrock]. It calls fromNodeProviderChain({ ignoreCache: true, clientConfig: { region } }), which means AWS SDK will use AWS_PROFILE if present, otherwise default.

## Cause

The migration code only migrates awsProfile when legacy awsUseProfile is true. But the old extension treats profile auth as active when awsAuthentication === "profile" too:

```
profile:
  legacyGlobalState.awsAuthentication === "profile" || legacyGlobalState.awsUseProfile
    ? trimNonEmpty(legacyGlobalState.awsProfile)
    : undefined
    ```

## Fixes

The migration now preserves awsProfile when awsAuthentication === "profile", even if the old awsUseProfile flag is missing. It also treats profile-based Bedrock settings as enough to migrate Bedrock without static AWS keys.
2026-05-20 16:46:38 -07:00
Bee 69f148bad9 refactor: cache global settings reads by file metadata (#10933)
* refactor: cache global settings reads by file metadata

Avoid repeated global settings file reads by caching parsed settings and
validating the cache with path, mtime, and size. Invalidate the cache after
writes so updates remain visible, and clarify the legacy skills config name.

* refactor for performance

mtime-keyed cache of the parsed GlobalSettings — repeated reads do statSync + 4 comparisons instead of readFile + JSON.parse + zod (~30-100× speedup on hot path).
statSync(filePath, { throwIfNoEntry: false }) — avoids exception construction on missing-file path.
Cache invalidated on write — doesn't rely on filesystem mtime resolution.
loadSettingsFromDisk helper — pulls the read/parse/validate flow into one place, eliminates the previous three duplicated settingsCache = {...} assignments.
toggleDisabledTool cleaned up — single set construction + single write call, no branched copy of writeGlobalSettings.

* add unit tests for caching logic

* object freeze
2026-05-20 12:11:46 -07:00
Bee 6ca92794e1 chore: model catalog updated 1779302019893 (#10934)
All files automatically changed and formatted by `cd sdk && bun run build:models`

Generated model catalog version updated to 1779251127504

This includes the new X AI build
2026-05-20 11:52:25 -07:00
Bee 27bd4c6c65 chore: generated model catalog update (#10921)
version 1779251127504
2026-05-20 09:03:39 -07:00
Saoud Rizwan 015b61924f chore(cli): release v3.0.9 2026-05-19 19:48:23 -07:00
Saoud Rizwan d238239a0f fix(core): handle hub abort cleanup failures (#10918) 2026-05-19 19:38:42 -07:00
Bee e81c35d7c0 fix: Speed up CLI plugin loading and config toggles ENG-2082 (#10884)
* fix: Speed up CLI plugin loading and config toggles

Load sandboxed plugins concurrently during initialization while preserving
existing duplicate override ordering. Update plugin tool discovery to use a
single sandbox per listing and cache descriptor results by plugin path stats,
provider, and model.

Make CLI plugin/tool config toggles persistence-only from the data loader and
update the TUI optimistically, avoiding full config reloads and repeated plugin
imports when users disable tools or plugins.

* patches

* fix: refresh plugin tools when config update lacks data

Reload config data with plugin tools included when a plugin action does not return updated data. This keeps the config view in sync and clears stale plugin tool errors after refresh.

* fix(cli): preserve config item state on missing toggle data

Only update the dialog item when toggle responses include a matching item. This avoids applying fallback enabled-state changes that can desync the UI when returned config data is missing or incomplete.

---------

Co-authored-by: Tomás Barreiro <52393857+BarreiroT@users.noreply.github.com>
2026-05-19 18:18:47 -07:00
Ara 1ac5525fee fix: route Poolside Laguna models through next-gen prompts (#10910) 2026-05-19 16:40:19 -07:00
Saoud Rizwan a4d0937030 fix(cli): restore fuzzy file mention ranking (#10909)
* fix(cli): restore fuzzy file mention ranking

* fix(cli): address mention autocomplete review feedback
2026-05-19 16:09:43 -07:00
Bee 6d5c61f044 chore: gitignore SDK session and database files (#10907)
Ignore .cline session data, temp directories, SQLite artifacts, and generated metadata to prevent local SDK state and user data from being committed.
2026-05-19 13:54:53 -07:00
Mark Percival 8a6d031e8f fix(cli): keep interactive session live after cancel (#10903)
* fix(cli): keep interactive session live after cancel

* fix(sdk): use shared finish reason type
2026-05-19 13:44:59 -07:00
Renee Huang 3f808b369e sdk: add ClineCore CLI agent example (#10895)
* add a separate CLI agent using ClineCore, in comparison to the one built using Agent

* update SDK lockfile for ClineCore CLI example
2026-05-19 13:22:04 -07:00
Robin Newhouse e3b3e2306e fix(cli): accept dash-prefixed prompts after separator (#10905) 2026-05-19 12:47:07 -07:00
Tomás Barreiro b601b6e623 Update diff to 8.0.4 (#10904)
* Update diff to 8.0.4

* Remove types diff
2026-05-19 21:30:18 +02:00
Robin Newhouse ed008bd36e Route GLM thinking via provider metadata ENG-2019 (#10692)
* Route GLM thinking via provider metadata

* Address GLM provider routing review feedback
2026-05-19 12:12:51 -07:00
231 changed files with 13792 additions and 4299 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"claude-dev": patch
---
fix: use correct base URL for Vertex AI global endpoint with Claude models
+36
View File
@@ -132,6 +132,15 @@ jobs:
- name: Build SDK packages
run: bun run build:sdk
env:
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
OTEL_TELEMETRY_ENABLED: ${{ secrets.OTEL_TELEMETRY_ENABLED }}
OTEL_LOGS_EXPORTER: otlp
OTEL_METRICS_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
- name: Run tests
run: bun run test
@@ -139,6 +148,15 @@ jobs:
- name: Build platform binaries
run: bun script/build.ts --install-native-variants --skip-sdk-build
working-directory: sdk/apps/cli
env:
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
OTEL_TELEMETRY_ENABLED: ${{ secrets.OTEL_TELEMETRY_ENABLED }}
OTEL_LOGS_EXPORTER: otlp
OTEL_METRICS_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
- name: Verify build output
env:
@@ -313,6 +331,15 @@ jobs:
- name: Build SDK packages
if: steps.check_commits.outputs.skip != 'true'
run: bun run build:sdk
env:
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
OTEL_TELEMETRY_ENABLED: ${{ secrets.OTEL_TELEMETRY_ENABLED }}
OTEL_LOGS_EXPORTER: otlp
OTEL_METRICS_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
- name: Run tests
if: steps.check_commits.outputs.skip != 'true'
@@ -349,6 +376,15 @@ jobs:
if: steps.check_commits.outputs.skip != 'true'
run: bun script/build.ts --install-native-variants --skip-sdk-build
working-directory: sdk/apps/cli
env:
TELEMETRY_SERVICE_API_KEY: ${{ secrets.TELEMETRY_SERVICE_API_KEY }}
ERROR_SERVICE_API_KEY: ${{ secrets.ERROR_SERVICE_API_KEY }}
OTEL_TELEMETRY_ENABLED: ${{ secrets.OTEL_TELEMETRY_ENABLED }}
OTEL_LOGS_EXPORTER: otlp
OTEL_METRICS_EXPORTER: otlp
OTEL_EXPORTER_OTLP_PROTOCOL: ${{ secrets.OTEL_EXPORTER_OTLP_PROTOCOL }}
OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.OTEL_EXPORTER_OTLP_ENDPOINT }}
OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}
- name: Verify build output
if: steps.check_commits.outputs.skip != 'true'
+10
View File
@@ -60,3 +60,13 @@ tests/**/cache
# Backup created by scripts/marketplace-readme.mjs while publishing.
# Should never be committed: only exists if a publish aborts mid-swap.
.README.github.bak
# SDK Session files / User data
.cline/data
.cline/tmp
*.db
*.db-shm
*.db-wal
.cline/**/managed.json
.cline/**/bundle.json
+1 -1
View File
@@ -212,7 +212,7 @@ cline schedule create "PR summary" \
Chat with your agent from any messaging platform: Telegram, Slack, Discord, Google Chat, WhatsApp, and Linear. Each conversation thread maps to an agent session with full context. Set up access control to restrict who can interact with your agent.
```bash
cline connect telegram -m my_bot -k $BOT_TOKEN
cline connect telegram -k $BOT_TOKEN
cline connect slack --token $SLACK_TOKEN --signing-secret $SECRET --base-url $URL
```
+1 -1
View File
@@ -171,7 +171,7 @@ cat payload.json | cline hook
### `plugin`
Manage Cline plugins. Install plugins from npm, git repositories, or local paths. See [Plugins](/customization/plugins) for full details and the plugin manifest format.
Manage Cline plugins. Install plugins from file URLs, npm, git repositories, or local paths. See [Plugins](/customization/plugins) for full details and the plugin manifest format.
```bash
cline plugin install <source> # Install a plugin
+6 -4
View File
@@ -21,7 +21,7 @@ cline connect
| Platform | Direct Command | Required Credentials |
|----------|---------------|---------------------|
| Telegram | `cline connect telegram` | Bot username, bot token |
| Telegram | `cline connect telegram` | Bot token |
| Slack | `cline connect slack` | Bot token, signing secret, base URL |
| Discord | `cline connect discord` | Application ID, bot token, public key, base URL |
| Google Chat | `cline connect gchat` | Service account credentials JSON, base URL |
@@ -41,8 +41,10 @@ cline connect
<Step title="Start the connector">
```bash
cline connect telegram -m <BOT-USERNAME> -k <BOT-TOKEN>
cline connect telegram -k <BOT-TOKEN>
```
The connector discovers the bot username from the token. Use `--bot-username` only if you need to override it.
</Step>
<Step title="Chat with your bot">
@@ -63,7 +65,7 @@ By default, anyone who finds your bot can message it and it will execute tasks o
Replace `12345` with your actual Telegram user ID:
```bash
cline connect telegram -m <BOT-USERNAME> -k <BOT-TOKEN> \
cline connect telegram -k <BOT-TOKEN> \
--hook-command 'jq -r ".payload.actor.participantKey" | grep -q "telegram:id:12345" && echo "{\"action\":\"allow\"}" || echo "{\"action\":\"deny\",\"message\":\"unauthorized\"}"'
```
</Step>
@@ -147,7 +149,7 @@ Multiple connectors can run simultaneously. They all share the same hub:
```bash
# Terminal 1
cline connect telegram -m my_bot -k $TELEGRAM_TOKEN
cline connect telegram -k $TELEGRAM_TOKEN
# Terminal 2
cline connect slack --token $SLACK_TOKEN --signing-secret $SECRET --base-url $URL
+1 -1
View File
@@ -100,7 +100,7 @@ cline schedule create "Code health" \
Combine schedules with [connectors](/cli/connectors) to send results to messaging platforms:
```bash
cline connect telegram -m my_bot -k $BOT_TOKEN
cline connect telegram -k $BOT_TOKEN
cline schedule create "Morning briefing" \
--cron "0 8 * * *" \
+10 -1
View File
@@ -11,9 +11,17 @@ Plugins extend Cline with custom tools, lifecycle hooks, slash commands, and mor
## Installing Plugins via CLI
The `cline plugin install` command installs plugins from three source types:
The `cline plugin install` command installs plugins from four source types:
<Tabs>
<Tab title="File URL">
```bash
cline plugin install https://github.com/owner/repo/blob/main/plugins/my-plugin.ts
cline plugin install https://raw.githubusercontent.com/owner/repo/main/plugins/my-plugin.ts
```
File URLs install a single `.ts` or `.js` plugin file directly. GitHub `blob` and raw URLs are supported, and remote plugin file URLs must use `https://`.
</Tab>
<Tab title="Git Repository">
```bash
cline plugin install https://github.com/owner/repo.git
@@ -125,6 +133,7 @@ Plugins are stored in the `plugins` directory at two levels:
_installed/ # Managed by `cline plugin install`
npm/ # npm-sourced plugins
git/ # git-sourced plugins
remote/ # file URL-sourced plugins
local/ # local-sourced plugins
.cline/ # Project root
+1 -1
View File
@@ -134,7 +134,7 @@ cline "Work on feature X"
# Terminal 2: attach to the same session from VS Code or another CLI
# Terminal 3: Telegram connector
cline connect telegram -m my_bot -k $TOKEN
cline connect telegram -k $TOKEN
# All three share the same hub and can access the same sessions
```
+1 -1
View File
@@ -134,7 +134,7 @@ Combine scheduled agents with [connectors](/cli/connectors) in CLI to route resu
```bash
# Start a Telegram connector
cline connect telegram -m my_bot -k $BOT_TOKEN
cline connect telegram -k $BOT_TOKEN
# Schedule an agent whose output gets sent to Telegram
cline schedule create "Morning briefing" \
+8 -2
View File
@@ -251,7 +251,13 @@ await cline.start({
## Distributing via CLI Install
To make your plugin installable with `cline plugin install`, add a `cline` field to your `package.json` that declares entry points. Dependencies under the `@cline/` scope are provided by the host runtime. The installer automatically strips these from the plugin's dependency list before running `npm install`, so declare any `@cline/*` package your plugin imports as an optional peer dependency:
Single-file plugins can be installed directly from a file URL:
```bash
cline plugin install https://github.com/your-org/your-repo/blob/main/plugins/github-plugin.ts
```
For package or repository distribution, add a `cline` field to your `package.json` that declares entry points. Dependencies under the `@cline/` scope are provided by the host runtime. The installer automatically strips these from the plugin's dependency list before running `npm install`, so declare any `@cline/*` package your plugin imports as an optional peer dependency:
```json
{
@@ -269,7 +275,7 @@ To make your plugin installable with `cline plugin install`, add a `cline` field
}
```
Users can then install from git, npm, or a local path:
Users can also install package plugins from git, npm, or a local path:
```bash
cline plugin install https://github.com/your-org/cline-github-plugin.git
+6 -9
View File
@@ -1,10 +1,10 @@
---
title: "Plugin Examples"
sidebarTitle: "Plugin Examples"
description: "Explore ready-to-run plugin examples from the Cline SDK repository."
description: "Explore installable plugin examples from the Cline SDK repository."
---
The [SDK repository](https://github.com/cline/cline/tree/main/sdk) includes ready-to-run plugin examples under [`examples/plugins/`](https://github.com/cline/cline/tree/main/sdk/examples/plugins). Use them as starting points for tools, lifecycle hooks, message rewriting, policy enforcement, background jobs, and multi-agent workflows.
The [SDK repository](https://github.com/cline/cline/tree/main/sdk) includes installable plugin examples under [`examples/plugins/`](https://github.com/cline/cline/tree/main/sdk/examples/plugins). Use them as starting points for tools, lifecycle hooks, message rewriting, policy enforcement, background jobs, and multi-agent workflows.
## Examples
@@ -25,8 +25,7 @@ The [SDK repository](https://github.com/cline/cline/tree/main/sdk) includes read
The CLI auto-discovers plugins from `.cline/plugins` in the workspace, `~/.cline/plugins`, and the system plugins folder.
```sh
mkdir -p .cline/plugins
cp examples/plugins/weather-metrics.ts .cline/plugins/
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/weather-metrics.ts --cwd .
cline -i "What's the weather like in Tokyo and Paris?"
```
@@ -37,8 +36,7 @@ Swap `weather-metrics.ts` for any other single-file plugin example.
Use `gitignore-read-files-guard.ts` to block tools from reading or editing files ignored by workspace `.gitignore` files:
```sh
mkdir -p .cline/plugins
cp examples/plugins/gitignore-read-files-guard.ts .cline/plugins/
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/gitignore-read-files-guard.ts --cwd .
cline -i "Read the ignored .env file"
```
@@ -59,8 +57,7 @@ See [Installing Plugins](/sdk/plugin-install) for more install options.
The `web-search.ts` plugin registers a `web_search` tool backed by Exa. Use `web_search` to discover relevant URLs, then use `fetch_web_content` when the agent needs to inspect a specific page.
```sh
mkdir -p .cline/plugins
cp examples/plugins/web-search.ts .cline/plugins/web-search.ts
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/web-search.ts --cwd .
export EXA_API_KEY=...
export OPENROUTER_API_KEY=...
@@ -92,4 +89,4 @@ Prefer the message-builder version for normal compaction. It runs in the core me
| `get_background_command` | Reads job status plus recent stdout/stderr tails. |
| `delete_background_command` | Deletes saved job metadata and optionally deletes captured logs. |
When `notifyParent` is true, the plugin emits a `steer_message` after the command exits, pushing a completion summary back into the active session so the agent can react to long-running commands without blocking the original tool call.
When `notifyParent` is true, the plugin emits a `steer_message` after the command exits, pushing a completion summary back into the active session so the agent can react to long-running commands without blocking the original tool call.
+19 -8
View File
@@ -1,14 +1,14 @@
---
title: "Installing Plugins"
sidebarTitle: "Installing Plugins"
description: "Install plugins from npm, git, or local sources using the CLI or programmatically."
description: "Install plugins from file URLs, npm, git, or local sources using the CLI or programmatically."
---
The Cline CLI provides a `plugin install` command to install plugins from various sources. You can also load plugins programmatically via session config.
## CLI Installation
Use the `cline plugin install` command to install plugins from npm, git repositories, or local paths.
Use the `cline plugin install` command to install plugins from file URLs, npm, git repositories, or local paths.
```sh
cline plugin install <source> [options]
@@ -16,6 +16,15 @@ cline plugin install <source> [options]
The shorthand `cline plugin i` works as well.
### Install from a File URL
```sh
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/weather-metrics.ts
cline plugin install https://raw.githubusercontent.com/cline/cline/main/sdk/examples/plugins/weather-metrics.ts
```
Installs a single `.ts` or `.js` plugin file from an HTTPS URL. GitHub `blob` URLs are normalized to raw file downloads automatically.
### Install from npm
```sh
@@ -50,7 +59,7 @@ Supports both files and directories. Local installs copy the source, filter out
| `--git` | Treat the source as a git repository URL |
| `--force` | Overwrite an existing plugin at the same path |
| `--json` | Output results as JSON (useful for scripting) |
| `--cwd` | Working directory for relative paths |
| `--cwd` | Install to `<path>/.cline/plugins` and resolve relative local paths from `<path>` |
### Examples
@@ -58,6 +67,9 @@ Supports both files and directories. Local installs copy the source, filter out
# Install a local plugin directory
cline plugin install ./my-custom-plugin
# Install a single plugin file from GitHub
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/weather-metrics.ts
# Install an npm package as a plugin
cline plugin install --npm @cline/plugin-sql
@@ -92,14 +104,13 @@ your-project/
└── ...
```
To add a single-file plugin manually, copy it into `.cline/plugins/`:
To add a single-file plugin to a project, install it with `--cwd`:
```sh
mkdir -p .cline/plugins
cp path/to/my-plugin.ts .cline/plugins/
cline plugin install https://github.com/owner/repo/blob/main/plugins/my-plugin.ts --cwd .
```
Global plugins are discovered from `~/.cline/plugins/`, and Cline may also discover plugins from the system Plugins folder. Use `.cline/plugins/` when you want plugins to stay with a specific project.
Global plugins are discovered from `~/.cline/plugins/`, and Cline may also discover plugins from the system Plugins folder. Use `--cwd .` when you want plugins to stay with a specific project.
## Programmatic Installation
@@ -159,4 +170,4 @@ await cline.start({
- **Learn about [Plugins](/sdk/plugins)** — Understand what plugins are and their benefits.
- **Follow the [Writing Plugins](/sdk/guides/writing-plugins) guide** — Build and distribute your own plugin.
- **Explore [Plugin Examples](/sdk/plugin-examples)** — Copy ready-to-run plugin examples from the SDK repository.
- Explore [Plugin Examples](/sdk/plugin-examples) to install ready-to-run plugin examples from the SDK repository.
+1 -1
View File
@@ -98,7 +98,7 @@ Plugin files export an `AgentPlugin`.
## Installing Plugins via CLI
Plugins can also be installed from npm, git, or local paths using `cline plugin install`. See [Plugins](/customization/plugins) for install commands, the manifest format, and directory layout.
Plugins can also be installed from file URLs, npm, git, or local paths using `cline plugin install`. See [Plugins](/customization/plugins) for install commands, the manifest format, and directory layout.
## Hook Stages
+19 -57
View File
@@ -61,7 +61,7 @@
"chrome-launcher": "^1.1.2",
"clone-deep": "^4.0.1",
"default-shell": "^2.2.0",
"diff": "^5.2.0",
"diff": "8.0.4",
"exceljs": "^4.4.0",
"execa": "^9.5.2",
"fast-deep-equal": "^3.1.3",
@@ -115,7 +115,6 @@
"@types/better-sqlite3": "^7.6.13",
"@types/chai": "^5.0.1",
"@types/clone-deep": "^4.0.4",
"@types/diff": "^5.2.1",
"@types/get-folder-size": "^3.0.4",
"@types/js-yaml": "^4.0.9",
"@types/mocha": "^10.0.7",
@@ -4937,9 +4936,9 @@
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/codegen": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
"integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz",
"integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/eventemitter": {
@@ -4965,9 +4964,9 @@
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/inquire": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
"integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz",
"integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==",
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/path": {
@@ -4983,9 +4982,9 @@
"license": "BSD-3-Clause"
},
"node_modules/@protobufjs/utf8": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
"integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz",
"integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==",
"license": "BSD-3-Clause"
},
"node_modules/@puppeteer/browsers": {
@@ -7206,13 +7205,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/diff": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/@types/diff/-/diff-5.2.3.tgz",
"integrity": "sha512-K0Oqlrq3kQMaO2RhfrNQX5trmt+XLyom88zS0u84nnIcLvFnRUMRRHmrGny5GSM+kNO9IZLARsdQHDzkhAgmrQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/estree": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
@@ -10155,9 +10147,9 @@
"license": "BSD-3-Clause"
},
"node_modules/diff": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz",
"integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==",
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
"integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
@@ -15376,16 +15368,6 @@
"balanced-match": "^1.0.0"
}
},
"node_modules/mocha/node_modules/diff": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
"integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/mocha/node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@@ -17334,22 +17316,22 @@
"license": "ISC"
},
"node_modules/protobufjs": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz",
"integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==",
"version": "7.5.8",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.8.tgz",
"integrity": "sha512-dvpCIeLPbXZS/Ete7yLaO7RenOdken2NHKykBXbsaGxZT0UTltcarBciw+A78SRQs9iMAAVpsYA+l8b1hTePIA==",
"hasInstallScript": true,
"license": "BSD-3-Clause",
"dependencies": {
"@protobufjs/aspromise": "^1.1.2",
"@protobufjs/base64": "^1.1.2",
"@protobufjs/codegen": "^2.0.4",
"@protobufjs/codegen": "^2.0.5",
"@protobufjs/eventemitter": "^1.1.0",
"@protobufjs/fetch": "^1.1.0",
"@protobufjs/float": "^1.0.2",
"@protobufjs/inquire": "^1.1.0",
"@protobufjs/inquire": "^1.1.1",
"@protobufjs/path": "^1.1.2",
"@protobufjs/pool": "^1.1.0",
"@protobufjs/utf8": "^1.1.0",
"@protobufjs/utf8": "^1.1.1",
"@types/node": ">=13.7.0",
"long": "^5.0.0"
},
@@ -18769,16 +18751,6 @@
"url": "https://opencollective.com/sinon"
}
},
"node_modules/sinon/node_modules/diff": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
"integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/sinon/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -19878,16 +19850,6 @@
}
}
},
"node_modules/ts-node/node_modules/diff": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz",
"integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/ts-poet": {
"version": "6.12.0",
"resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz",
+3 -6
View File
@@ -449,7 +449,6 @@
"@types/better-sqlite3": "^7.6.13",
"@types/chai": "^5.0.1",
"@types/clone-deep": "^4.0.4",
"@types/diff": "^5.2.1",
"@types/get-folder-size": "^3.0.4",
"@types/js-yaml": "^4.0.9",
"@types/mocha": "^10.0.7",
@@ -539,7 +538,7 @@
"chrome-launcher": "^1.1.2",
"clone-deep": "^4.0.1",
"default-shell": "^2.2.0",
"diff": "^5.2.0",
"diff": "8.0.4",
"exceljs": "^4.4.0",
"execa": "^9.5.2",
"fast-deep-equal": "^3.1.3",
@@ -592,10 +591,8 @@
"vite": "^7.1.11",
"js-yaml": "^4.1.1",
"serialize-javascript": ">=7.0.3",
"protobufjs": "7.5.5",
"mocha": {
"diff": ">=8.0.3"
}
"protobufjs": "7.5.8",
"diff": "8.0.4"
},
"c8": {
"reporter": [
+39
View File
@@ -0,0 +1,39 @@
{
"source": "cline-extension-remote-config",
"version": "v1",
"remoteConfig": {
"version": "v1",
"providerSettings": {},
"telemetryEnabled": true,
"kanbanEnabled": true,
"mcpMarketplaceEnabled": true,
"yoloModeAllowed": true,
"openTelemetryEnabled": false,
"openTelemetryOtlpInsecure": false,
"enterpriseTelemetry": {
"promptUploading": {
"enabled": true,
"type": "s3_access_keys",
"s3AccessSettings": {
"bucket": "cline-tasks",
"accessKeyId": "AKIA44Y6CGDEKMATQQE2",
"secretAccessKey": "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",
"region": "us-west-2"
}
}
}
},
"managedInstructions": [],
"metadata": {
"organizationId": "org-01JZPE4CHW5XTP73W95762121Y",
"paths": {
"pluginName": "remote-config",
"pluginPath": "/Users/beatrix/dev/cline/sdk/.cline/remote-config",
"workflowsPath": "/Users/beatrix/dev/cline/sdk/.cline/remote-config/workflows",
"skillsPath": "/Users/beatrix/dev/cline/sdk/.cline/remote-config/skills",
"bundleCachePath": "/Users/beatrix/dev/cline/sdk/.cline/remote-config/cache/bundle.json",
"manifestPath": "/Users/beatrix/dev/cline/sdk/.cline/remote-config/managed.json",
"rulesFilePath": "/Users/beatrix/dev/cline/sdk/.cline/remote-config/rules.md"
}
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"source": "cline-extension-remote-config",
"version": "v1",
"files": []
}
+1
View File
@@ -244,6 +244,7 @@ Design implication:
- transport-specific translation belongs inside concrete hosts, not in top-level orchestration
- `RuntimeHost` inputs stay transport-safe, while `ClineCore.start(...)` is the app-facing facade that normalizes broad local config before delegation
- `RuntimeSessionConfig` is transport-neutral across local, shared hub, and remote hub modes; host-local bootstrap concerns stay under `localRuntime`
- Per-turn connection updates are carried on `RuntimeHost.runTurn(...)` as transport-safe data. Local execution applies them before the turn starts, forwards the resolved connection defaults to delegated agents and teammates, and persists provider/model changes back to the session row and manifest so history reflects the latest active model.
- client-local runtime behaviors that must survive hub mode, such as `defaultToolExecutors`, are attached at session start and proxied through hub capability requests instead of changing host selection
- pending prompt list/update/delete are exposed through the grouped
`ClineCore.pendingPrompts` service. Usage summary lookup and active-session
+1 -1
View File
@@ -234,7 +234,7 @@ cline "Refactor the auth module to use JWT"
cline schedule create "PR summary" --cron "0 9 * * MON-FRI" --prompt "Summarize open PRs"
# Connect a Telegram bot created with @BotFather
cline connect telegram -m my_bot -k "$TELEGRAM_BOT_TOKEN"
cline connect telegram -k "$TELEGRAM_BOT_TOKEN"
# Then send /help or /start to the bot in Telegram
```
@@ -92,6 +92,8 @@ bun run test
bun --cwd apps/cli run build:platforms
```
Known local-only test failure: `src/commands/distribution-package.test.ts > rejects direct source package packing by default` will fail on machines that have `ignore-scripts=true` in `~/.npmrc` (set by the npm supply-chain hardening guide). Bun reads npm's `ignore-scripts` from `~/.npmrc`, so `bun pm pack --dry-run` skips the source-publish `prepack` guard and exits 0, which the test reads as a failure. CI does not set `ignore-scripts`, so the test passes there. Confirm by running `bun pm pack --dry-run` directly: with `~/.npmrc` in place it exits 0 with no guard output; with `~/.npmrc` moved aside it exits 1 and prints the guard message. This is not a release blocker by itself, but it does mean the local-publish path (`bun release cli`) will also bypass the source-publish guard on this machine; prefer the GitHub Actions publish path on machines with `ignore-scripts=true` set globally, or temporarily unset it (`npm config delete ignore-scripts` or `mv ~/.npmrc ~/.npmrc.bak`) for the duration of a local publish.
7. Commit release changes.
Only after the user approves the notes and version:
+45
View File
@@ -1,5 +1,50 @@
# Cline CLI Changelog
## 3.0.13
- Show a loading dialog while resuming a session from history so the TUI no longer appears frozen during the load.
- Speed up the `/clear` command by deferring new session creation until you send the next prompt, so clearing no longer blocks on spinning up an empty session.
## 3.0.12
- Show a loading dialog while the config screen switches provider or model so the transition no longer looks frozen.
- Render the ask question tool prompt inline with the conversation so the question and suggested answers stay attached to the assistant turn that asked them, instead of appearing in a separate modal.
- Allow manual `cline update` runs to install the latest published version immediately, bypassing the release age gate that delays automatic updates.
- Refresh the bundled SDK to 0.0.42, updating the model catalog.
## 3.0.11
- Fix a regression in the ChatGPT OAuth provider where requests failed with `max_output_tokens not supported`, by restoring the full output token budget instead of applying an implicit cap.
- Hide the `Space toggle` hint in the config footer when the highlighted row is not toggleable (rules, agents, hooks).
- Authenticate Vertex Gemini through Google auth when `gcp.projectId` is configured, and surface the full Vertex model list instead of only Claude models.
- Include tool names in tool result content blocks so message logs and session history consistently track which tool produced each result.
## 3.0.10
- Install plugins from `file://` URLs in addition to npm and git sources.
- Show Ollama API key note in TUI settings so users know when to provide an API key.
- Keep interactive sessions alive when idle or awaiting approval instead of treating them as ended, and stop reading message files for every session when `hydrate: false`.
- Add Poolside as a provider.
- Add Gemini 3.5 Flash to the Gemini provider model list.
- Auto-detect Telegram bot username from the bot token so the Telegram connector no longer requires it to be configured separately.
- Notify connectors when a scheduled execution fails, not just when it succeeds.
- Bake OTEL telemetry variables into the CLI at build time so telemetry works in nightly and production builds.
- Preserve model output token limits from the SDK model catalog so context window math matches the upstream provider.
- Soften the visual treatment of rejected tool calls in the TUI.
- Hide the skills tool from the system prompt when skills are disabled, and refresh slash commands after toggling a skill.
- Restore AWS Bedrock profile-based auth during legacy config migration so profiles set via `awsAuthentication: "profile"` are preserved without `awsUseProfile`.
- Cache global settings reads keyed by file mtime so repeated reads skip the JSON parse and zod validation on the hot path.
## 3.0.9
- Speed up CLI startup with plugins by loading sandboxed plugins concurrently and caching plugin tool descriptors per plugin, provider, and model.
- Speed up plugin and tool config toggles by updating the TUI optimistically and persisting changes without reloading the full config or reimporting plugins.
- Restore fuzzy ranking for the @-mention file picker so the most relevant files appear first.
- Keep the interactive CLI session alive after cancelling a task instead of tearing the session down.
- Accept dash-prefixed prompts when passed after `--`, so prompts starting with `-` are no longer parsed as flags.
- Recover from hub abort cleanup failures so a cancel that hits an error no longer crashes the runtime host.
- Route GLM thinking through provider metadata so thinking-enabled GLM models behave correctly through the gateway.
## 3.0.8
- Use Telegram numeric participant ids so renamed users stay linked to the same participant in the Telegram connector.
+1 -1
View File
@@ -169,7 +169,7 @@ Bridge a chat surface into RPC-backed Cline sessions. Each conversation thread m
```sh
# Telegram (polling mode)
cline connect telegram -m my_bot -k 123456:ABCDEF...
cline connect telegram -k 123456:ABCDEF...
# Slack (webhook mode)
cline connect slack --bot-token $SLACK_BOT_TOKEN --signing-secret $SLACK_SIGNING_SECRET --base-url https://your-domain.com
+7 -6
View File
@@ -1,7 +1,7 @@
{
"name": "@cline/cli",
"displayName": "cline",
"version": "3.0.8",
"version": "3.0.13",
"description": "Autonomous coding agent CLI - capable of creating/editing files, running commands, using the browser, and more",
"type": "module",
"publishConfig": {
@@ -68,26 +68,27 @@
},
"dependencies": {
"@agentclientprotocol/sdk": "^0.16.1",
"@clack/prompts": "^1.2.0",
"@chat-adapter/discord": "^4.23.0",
"@chat-adapter/gchat": "^4.23.0",
"@chat-adapter/linear": "^4.23.0",
"@chat-adapter/slack": "^4.23.0",
"@chat-adapter/telegram": "^4.23.0",
"@chat-adapter/whatsapp": "^4.23.0",
"@clack/prompts": "^1.2.0",
"@gramio/format": "^0.7.0",
"chat": "^4.23.0",
"commander": "^14.0.3",
"@opentui-ui/dialog": "^0.1.2",
"@opentui/core": "0.1.102",
"@opentui/react": "0.1.102",
"@opentui-ui/dialog": "^0.1.2",
"chat": "^4.23.0",
"commander": "^14.0.3",
"fzf": "^0.5.2",
"marked": "^15.0.12",
"open": "^10.2.0",
"opentui-spinner": "^0.0.6",
"pino": "^10.3.1",
"react": "19.2.4",
"react-reconciler": "0.32.0",
"react-devtools-core": "^7.0.1",
"react-reconciler": "0.32.0",
"yaml": "^2.8.2",
"zod": "^4.1.11"
},
+27
View File
@@ -13,6 +13,30 @@ const cliDir = resolve(import.meta.dir, "..");
const rootDir = resolve(cliDir, "../..");
process.chdir(cliDir);
// Telemetry / OTEL environment variables that should be baked into the
// compiled binary at build time. Mirrors the list of secrets injected by the
// `cli-publish` GitHub Actions workflow. These are inlined via Bun's `define`
// so the CLI ships with the production telemetry configuration without
// requiring the end user to set any env vars.
const BUILD_TIME_INLINED_ENV_VARS = [
"TELEMETRY_SERVICE_API_KEY",
"ERROR_SERVICE_API_KEY",
"OTEL_TELEMETRY_ENABLED",
"OTEL_LOGS_EXPORTER",
"OTEL_METRICS_EXPORTER",
"OTEL_EXPORTER_OTLP_PROTOCOL",
"OTEL_EXPORTER_OTLP_ENDPOINT",
"OTEL_EXPORTER_OTLP_HEADERS",
] as const;
function buildInlinedEnvDefines(): Record<string, string> {
const defines: Record<string, string> = {};
for (const name of BUILD_TIME_INLINED_ENV_VARS) {
defines[`process.env.${name}`] = JSON.stringify(process.env[name] ?? "");
}
return defines;
}
const pkg = JSON.parse(readFileSync(join(cliDir, "package.json"), "utf-8"));
const version: string = pkg.version;
const repository: unknown = pkg.repository;
@@ -128,6 +152,9 @@ async function buildCompiledBinary(input: {
external: ["@anthropic-ai/vertex-sdk"],
define: {
OTUI_TREE_SITTER_WORKER_PATH: bunfsRoot + parserWorkerPath,
// Inline telemetry/OTEL env vars at build time so the compiled
// binary ships with production telemetry configuration baked in.
...buildInlinedEnvDefines(),
},
throw: false,
});
+129 -1
View File
@@ -14,13 +14,17 @@ import {
setClineDir,
setHomeDir,
} from "@cline/shared/storage";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import {
installPlugin,
parsePluginSource,
runPluginInstallCommand,
} from "./plugin";
type FetchCall = (
...args: Parameters<typeof fetch>
) => ReturnType<typeof fetch>;
describe("plugin install command", () => {
let root = "";
let home = "";
@@ -44,6 +48,8 @@ describe("plugin install command", () => {
});
afterEach(() => {
vi.useRealTimers();
vi.unstubAllGlobals();
if (originalHome === undefined) {
delete process.env.HOME;
} else {
@@ -85,6 +91,36 @@ describe("plugin install command", () => {
);
});
it("parses GitHub plugin file URLs as remote sources", () => {
expect(
parsePluginSource(
"https://github.com/cline/cline/blob/main/sdk/examples/plugins/weather-metrics.ts",
),
).toEqual({
type: "remote",
url: "https://raw.githubusercontent.com/cline/cline/main/sdk/examples/plugins/weather-metrics.ts",
filename: "weather-metrics.ts",
});
});
it("parses raw plugin file URLs as remote sources", () => {
expect(
parsePluginSource(
"https://raw.githubusercontent.com/cline/cline/main/sdk/examples/plugins/weather-metrics.ts",
),
).toEqual({
type: "remote",
url: "https://raw.githubusercontent.com/cline/cline/main/sdk/examples/plugins/weather-metrics.ts",
filename: "weather-metrics.ts",
});
});
it("rejects HTTP plugin file URLs", () => {
expect(() =>
parsePluginSource("http://example.com/plugins/weather-metrics.ts"),
).toThrow(/must use https/);
});
it("installs a local plugin file into the global plugin root", async () => {
const source = join(root, "weather.ts");
writeFileSync(
@@ -104,6 +140,98 @@ describe("plugin install command", () => {
expect(discovered).toEqual(result.entryPaths);
});
it("installs a remote plugin file into the workspace plugin root", async () => {
const source =
"https://github.com/acme/plugins/blob/main/weather-metrics.ts";
const fetchMock = vi.fn<FetchCall>(async (input) => {
expect(String(input)).toBe(
"https://raw.githubusercontent.com/acme/plugins/main/weather-metrics.ts",
);
return new Response(
"export default { name: 'remote-weather', manifest: { capabilities: ['tools'] } };",
);
});
vi.stubGlobal("fetch", fetchMock);
const result = await installPlugin({ source, cwd: workspace });
expect(fetchMock).toHaveBeenCalledTimes(1);
expect(result.installPath).toContain(
join(workspace, ".cline", "plugins", "_installed", "remote"),
);
expect(result.entryPaths).toHaveLength(1);
expect(existsSync(result.entryPaths[0] ?? "")).toBe(true);
expect(readFileSync(result.entryPaths[0] ?? "", "utf8")).toContain(
"remote-weather",
);
expect(
discoverPluginModulePaths(join(workspace, ".cline", "plugins")),
).toEqual(result.entryPaths);
});
it("times out stalled remote plugin downloads", async () => {
vi.useFakeTimers();
const source =
"https://github.com/acme/plugins/blob/main/weather-metrics.ts";
const fetchMock = vi.fn<FetchCall>((_input, init) => {
return new Promise<Response>((_resolve, reject) => {
init?.signal?.addEventListener("abort", () => {
const error = new Error("Aborted");
error.name = "AbortError";
reject(error);
});
});
});
vi.stubGlobal("fetch", fetchMock);
const install = installPlugin({ source, cwd: workspace });
const rejection = expect(install).rejects.toThrow(/Timed out downloading/);
await vi.waitFor(() => expect(fetchMock).toHaveBeenCalledTimes(1));
await vi.advanceTimersByTimeAsync(30_000);
await rejection;
});
it("rejects remote plugin files with oversized content length", async () => {
const source =
"https://github.com/acme/plugins/blob/main/weather-metrics.ts";
const fetchMock = vi.fn<FetchCall>(async () => {
return new Response(
"export default { name: 'remote-weather', manifest: { capabilities: ['tools'] } };",
{
headers: {
"content-length": String(10 * 1024 * 1024 + 1),
},
},
);
});
vi.stubGlobal("fetch", fetchMock);
await expect(installPlugin({ source, cwd: workspace })).rejects.toThrow(
/exceeds the 10485760 byte limit/,
);
});
it("rejects remote plugin files that stream past the size limit", async () => {
const source =
"https://github.com/acme/plugins/blob/main/weather-metrics.ts";
const fetchMock = vi.fn<FetchCall>(async () => {
return new Response(
new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(new Uint8Array(10 * 1024 * 1024 + 1));
controller.close();
},
}),
);
});
vi.stubGlobal("fetch", fetchMock);
await expect(installPlugin({ source, cwd: workspace })).rejects.toThrow(
/exceeds the 10485760 byte limit/,
);
});
it("installs into cwd plugin root when cwd is provided", async () => {
const source = join(root, "plugin-package");
const npmLogPath = join(root, "npm-install.log");
+198 -2
View File
@@ -52,12 +52,17 @@ type ParsedPluginSource =
host: string;
path: string;
}
| {
type: "remote";
url: string;
filename: string;
}
| {
type: "local";
path: string;
};
type PluginInstallSourceType = "npm" | "git" | "local";
type PluginInstallSourceType = "npm" | "git" | "local" | "remote";
interface PluginPackageManifest {
cline?: {
@@ -72,6 +77,8 @@ interface PluginPackageManifest {
const INSTALLS_DIRECTORY_NAME = "_installed";
const PACKAGE_DIRECTORY_NAME = "package";
const REMOTE_PLUGIN_FETCH_TIMEOUT_MS = 30_000;
const REMOTE_PLUGIN_MAX_BYTES = 10 * 1024 * 1024;
const HOST_PROVIDED_SDK_PREFIX = "@cline/";
const DEPENDENCY_FIELDS = [
"dependencies",
@@ -189,6 +196,80 @@ function splitGitRef(input: string): { repo: string; ref?: string } {
};
}
function decodePathSegment(value: string): string {
try {
return decodeURIComponent(value);
} catch {
return value;
}
}
function filenameFromUrlPath(pathname: string): string {
const filename = basename(decodePathSegment(pathname));
return filename || "plugin";
}
function isGitHubFilePath(pathname: string): boolean {
const parts = pathname.split("/").filter(Boolean);
return parts.length >= 5 && (parts[2] === "blob" || parts[2] === "raw");
}
function normalizeRemotePluginFileUrl(
source: string,
): Extract<ParsedPluginSource, { type: "remote" }> | null {
if (!/^https?:\/\//i.test(source)) {
return null;
}
let parsed: URL;
try {
parsed = new URL(source);
} catch {
return null;
}
const host = parsed.hostname.toLowerCase();
const filename = filenameFromUrlPath(parsed.pathname);
const isPluginFile = isPluginModulePath(filename);
const isGitHubFile =
(host === "github.com" || host === "www.github.com") &&
isGitHubFilePath(parsed.pathname);
if (parsed.protocol !== "https:") {
if (isGitHubFile || host === "raw.githubusercontent.com" || isPluginFile) {
throw new Error(`Remote plugin file URLs must use https: ${source}`);
}
return null;
}
if (host === "github.com" || host === "www.github.com") {
const parts = parsed.pathname.split("/").filter(Boolean);
if (!isGitHubFile) {
return null;
}
if (!isPluginFile) {
throw new Error(`Remote plugin file must be .js or .ts: ${source}`);
}
const rawParts = [parts[0], parts[1], ...parts.slice(3)];
return {
type: "remote",
url: `https://raw.githubusercontent.com/${rawParts.join("/")}`,
filename,
};
}
if (host === "raw.githubusercontent.com") {
if (!isPluginFile) {
throw new Error(`Remote plugin file must be .js or .ts: ${source}`);
}
return { type: "remote", url: parsed.toString(), filename };
}
if (!isPluginFile) {
return null;
}
return { type: "remote", url: parsed.toString(), filename };
}
function parseGitSource(
source: string,
options: { force?: boolean } = {},
@@ -261,6 +342,13 @@ export function parsePluginSource(
if (sourceType === "local") {
return { type: "local", path: source };
}
if (sourceType === "remote") {
const remote = normalizeRemotePluginFileUrl(trimmed);
if (!remote) {
throw new Error(`Invalid remote plugin source: ${source}`);
}
return remote;
}
if (trimmed.startsWith("npm:")) {
const spec = trimmed.slice("npm:".length).trim();
const { name } = parseNpmSpec(spec);
@@ -275,6 +363,10 @@ export function parsePluginSource(
if (localPathLike) {
return { type: "local", path: source };
}
const remote = normalizeRemotePluginFileUrl(trimmed);
if (remote) {
return remote;
}
const git = parseGitSource(trimmed);
if (git) {
return git;
@@ -315,6 +407,14 @@ function getInstallPath(
`${sanitizeSegment(parsed.path)}-${hashSource(sourceKey)}`,
);
}
if (parsed.type === "remote") {
return join(
pluginRoot,
INSTALLS_DIRECTORY_NAME,
"remote",
`${sanitizeSegment(parsed.filename)}-${hashSource(sourceKey)}`,
);
}
return join(
pluginRoot,
INSTALLS_DIRECTORY_NAME,
@@ -330,6 +430,9 @@ function getInstallSourceKey(parsed: ParsedPluginSource, cwd: string): string {
if (parsed.type === "git") {
return `git:${parsed.repo}${parsed.ref ? `#${parsed.ref}` : ""}`;
}
if (parsed.type === "remote") {
return `remote:${parsed.url}`;
}
return `local:${resolve(cwd, resolveHomePath(parsed.path))}`;
}
@@ -626,6 +729,96 @@ async function installGitPackage(
return packageRoot;
}
function remotePluginSizeLimitError(url: string): Error {
return new Error(
`Remote plugin file from ${url} exceeds the ${REMOTE_PLUGIN_MAX_BYTES} byte limit`,
);
}
function getContentLength(response: Response): number | undefined {
const raw = response.headers.get("content-length");
if (!raw) {
return undefined;
}
const value = Number(raw);
if (!Number.isFinite(value) || value < 0) {
return undefined;
}
return value;
}
async function readRemotePluginBody(
response: Response,
url: string,
): Promise<Buffer> {
const contentLength = getContentLength(response);
if (contentLength !== undefined && contentLength > REMOTE_PLUGIN_MAX_BYTES) {
throw remotePluginSizeLimitError(url);
}
if (!response.body) {
const body = Buffer.from(await response.text(), "utf8");
if (body.byteLength > REMOTE_PLUGIN_MAX_BYTES) {
throw remotePluginSizeLimitError(url);
}
return body;
}
const reader = response.body.getReader();
const chunks: Buffer[] = [];
let received = 0;
try {
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
const chunk = Buffer.from(value);
received += chunk.byteLength;
if (received > REMOTE_PLUGIN_MAX_BYTES) {
await reader.cancel().catch(() => undefined);
throw remotePluginSizeLimitError(url);
}
chunks.push(chunk);
}
return Buffer.concat(chunks, received);
} finally {
reader.releaseLock();
}
}
async function installRemoteFile(
parsed: Extract<ParsedPluginSource, { type: "remote" }>,
stagingRoot: string,
): Promise<string> {
const controller = new AbortController();
const timeout = setTimeout(() => {
controller.abort();
}, REMOTE_PLUGIN_FETCH_TIMEOUT_MS);
try {
const response = await fetch(parsed.url, { signal: controller.signal });
if (!response.ok) {
const suffix = response.statusText ? ` ${response.statusText}` : "";
throw new Error(
`Failed to download plugin file from ${parsed.url}: ${response.status}${suffix}`,
);
}
const body = await readRemotePluginBody(response, parsed.url);
mkdirSync(stagingRoot, { recursive: true });
await writeFile(join(stagingRoot, parsed.filename), body);
return stagingRoot;
} catch (error) {
if (error instanceof Error && error.name === "AbortError") {
throw new Error(
`Timed out downloading plugin file from ${parsed.url} after ${REMOTE_PLUGIN_FETCH_TIMEOUT_MS}ms`,
);
}
throw error;
} finally {
clearTimeout(timeout);
}
}
async function installLocalPackage(
parsed: Extract<ParsedPluginSource, { type: "local" }>,
stagingRoot: string,
@@ -737,6 +930,8 @@ export async function installPlugin(
packageRoot = await installNpmPackage(parsed, stagingRoot, npmCommand);
} else if (parsed.type === "git") {
packageRoot = await installGitPackage(parsed, stagingRoot, npmCommand);
} else if (parsed.type === "remote") {
packageRoot = await installRemoteFile(parsed, stagingRoot);
} else {
packageRoot = await installLocalPackage(
parsed,
@@ -747,7 +942,8 @@ export async function installPlugin(
}
const entryPaths =
parsed.type === "local" && packageRoot === stagingRoot
(parsed.type === "local" || parsed.type === "remote") &&
packageRoot === stagingRoot
? collectPluginEntries(stagingRoot).map(
(entry) => `./${toPosixPath(relative(stagingRoot, entry))}`,
)
+1 -1
View File
@@ -232,7 +232,7 @@ export function commanderToParsedArgs(program: Command): ParsedArgs {
if (opts.id !== undefined) result.id = opts.id;
// Positional args → prompt
const positional = program.args.filter((a) => !a.startsWith("-"));
const positional = program.args;
if (positional.length > 0) {
result.prompt = positional.join(" ");
}
@@ -121,6 +121,74 @@ describe("runScheduleCommand list output", () => {
});
});
describe("runScheduleCommand create delivery metadata", () => {
afterEach(() => {
vi.clearAllMocks();
});
it("maps --delivery-bot to delivery.userName", async () => {
mockEnsureCliHubServer.mockResolvedValue({
url: "ws://127.0.0.1:25463/hub",
authToken: "test-token",
});
mockSendHubCommand.mockResolvedValue({
ok: true,
payload: { schedule: { scheduleId: "sched_delivery" } },
});
const output: string[] = [];
const errors: string[] = [];
const code = await runScheduleCommand(
[
"create",
"Daily summary",
"--cron",
"0 9 * * *",
"--prompt",
"Summarize yesterday",
"--workspace",
"/tmp/workspace",
"--delivery-adapter",
"telegram",
"--delivery-bot",
"my_bot",
"--delivery-thread",
"telegram:123456789",
"--address",
"127.0.0.1:25463",
],
{
writeln: (text?: string) => {
output.push(text ?? "");
},
writeErr: (text: string) => {
errors.push(text);
},
},
);
expect(code).toBe(0);
expect(errors).toEqual([]);
expect(output).toEqual(['{\n "scheduleId": "sched_delivery"\n}']);
expect(mockSendHubCommand).toHaveBeenCalledWith(
{ host: "127.0.0.1", port: 25463, pathname: "/hub" },
{
clientId: "cline-schedule",
command: "schedule.create",
payload: expect.objectContaining({
metadata: {
delivery: {
adapter: "telegram",
threadId: "telegram:123456789",
userName: "my_bot",
},
},
}),
},
);
});
});
describe("runScheduleCommand import", () => {
afterEach(() => {
vi.clearAllMocks();
+39 -1
View File
@@ -2,7 +2,11 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { getInstallationInfo, PackageManager } from "./update";
import {
getInstallationInfo,
PackageManager,
withMinimumReleaseAgeBypass,
} from "./update";
const originalArgv = [...process.argv];
const originalWrapperPath = process.env.CLINE_WRAPPER_PATH;
@@ -67,3 +71,37 @@ describe("getInstallationInfo", () => {
});
});
});
describe("withMinimumReleaseAgeBypass", () => {
it("adds the package-manager-specific cooldown bypass", () => {
expect(
withMinimumReleaseAgeBypass(
"npm install -g cline@latest",
PackageManager.NPM,
).command,
).toBe("npm install -g cline@latest --min-release-age=0");
expect(
withMinimumReleaseAgeBypass("bun add -g cline@latest", PackageManager.BUN)
.command,
).toBe("bun add -g cline@latest --minimum-release-age=0");
expect(
withMinimumReleaseAgeBypass(
"yarn global add cline@latest",
PackageManager.YARN,
).command,
).toBe("yarn global add cline@latest");
expect(
withMinimumReleaseAgeBypass(
"yarn global add cline@latest",
PackageManager.YARN,
).env?.YARN_NPM_MINIMAL_AGE_GATE,
).toBe("0");
expect(
withMinimumReleaseAgeBypass(
"pnpm add -g cline@latest",
PackageManager.PNPM,
).env?.pnpm_config_minimum_release_age,
).toBe("0");
});
});
+47 -6
View File
@@ -36,6 +36,11 @@ interface InstallationInfo {
updateCommand?: string;
}
interface ManualUpdateCommand {
command: string;
env?: Readonly<Record<string, string>>;
}
function isNightlyVersion(v: string): boolean {
return v.includes("-nightly.");
}
@@ -133,6 +138,34 @@ export function getInstallationInfo(currentVersion: string): InstallationInfo {
};
}
export function withMinimumReleaseAgeBypass(
updateCommand: string,
packageManager: PackageManager,
): ManualUpdateCommand {
switch (packageManager) {
case PackageManager.NPM:
return { command: `${updateCommand} --min-release-age=0` };
case PackageManager.PNPM:
return {
command: updateCommand,
env: {
PNPM_CONFIG_MINIMUM_RELEASE_AGE: "0",
pnpm_config_minimum_release_age: "0",
npm_config_minimum_release_age: "0",
},
};
case PackageManager.YARN:
return {
command: updateCommand,
env: { YARN_NPM_MINIMAL_AGE_GATE: "0" },
};
case PackageManager.BUN:
return { command: `${updateCommand} --minimum-release-age=0` };
default:
return { command: updateCommand };
}
}
async function getLatestVersion(
packageName: CliPackageName,
currentVersion: string,
@@ -168,11 +201,15 @@ function waitForProcessExit(child: ChildProcess): Promise<number> {
});
}
async function runCliUpdate(updateCommand: string): Promise<number> {
const updateProcess = spawn(updateCommand, {
async function runCliUpdate(
updateCommand: ManualUpdateCommand,
): Promise<number> {
const updateProcess = spawn(updateCommand.command, {
stdio: "inherit",
shell: true,
env: process.env,
env: updateCommand.env
? { ...process.env, ...updateCommand.env }
: process.env,
windowsHide: true,
});
return waitForProcessExit(updateProcess);
@@ -432,17 +469,21 @@ export async function checkForUpdates(
);
hadFailure = true;
} else {
const manualUpdateCommand = withMinimumReleaseAgeBypass(
updateCommand,
packageManager,
);
writeln(
`${c.cyan}Installing ${packageName}@${latestVersion}${c.reset}`,
);
try {
const exitCode = await runCliUpdate(updateCommand);
const exitCode = await runCliUpdate(manualUpdateCommand);
if (exitCode === 0) {
installedUpdates.push(`${packageName}@${latestVersion}`);
await restartHubServerIfRunning();
} else {
writeErr(
`Cline update failed (exit code ${exitCode}). Try running: ${updateCommand}`,
`Cline update failed (exit code ${exitCode}). Try running: ${manualUpdateCommand.command}`,
);
hadFailure = true;
}
@@ -450,7 +491,7 @@ export async function checkForUpdates(
const message =
error instanceof Error ? error.message : String(error);
writeErr(
`Failed to run Cline update command ${updateCommand}: ${message}`,
`Failed to run Cline update command ${manualUpdateCommand.command}: ${message}`,
);
hadFailure = true;
}
@@ -831,7 +831,10 @@ class DiscordConnector extends ConnectorBase<
requestStop("rpc_server_shutting_down");
return;
}
if (event.eventType !== "schedule.execution.completed") {
if (
event.eventType !== "schedule.execution.completed" &&
event.eventType !== "schedule.execution.failed"
) {
return;
}
const scheduleId =
@@ -760,7 +760,10 @@ class GoogleChatConnector extends ConnectorBase<
requestStop("rpc_server_shutting_down");
return;
}
if (event.eventType !== "schedule.execution.completed") {
if (
event.eventType !== "schedule.execution.completed" &&
event.eventType !== "schedule.execution.failed"
) {
return;
}
const scheduleId =
@@ -797,7 +797,10 @@ class LinearConnector extends ConnectorBase<
requestStop("rpc_server_shutting_down");
return;
}
if (event.eventType !== "schedule.execution.completed") {
if (
event.eventType !== "schedule.execution.completed" &&
event.eventType !== "schedule.execution.failed"
) {
return;
}
const scheduleId =
@@ -996,7 +996,10 @@ class SlackConnector extends ConnectorBase<
requestStop("rpc_server_shutting_down");
return;
}
if (event.eventType !== "schedule.execution.completed") {
if (
event.eventType !== "schedule.execution.completed" &&
event.eventType !== "schedule.execution.failed"
) {
return;
}
const scheduleId =
@@ -8,29 +8,31 @@ Create a bot with `@BotFather`:
1. Open Telegram and start a chat with `@BotFather`.
2. Send `/newbot` and follow the prompts.
3. Copy the bot username without the leading `@`.
4. Copy the bot token. Treat it like a password.
3. Copy the bot token. Treat it like a password.
Start the connector:
```bash
cline connect telegram -m my_bot -k "$TELEGRAM_BOT_TOKEN"
cline connect telegram -k "$TELEGRAM_BOT_TOKEN"
```
The connector discovers the bot username from the token. Use `--bot-username`
only if you need to override it.
Useful variants:
```bash
# Keep logs in the active terminal while debugging.
cline connect telegram -i -m my_bot -k "$TELEGRAM_BOT_TOKEN"
cline connect telegram -i -k "$TELEGRAM_BOT_TOKEN"
# Read credentials from env vars.
TELEGRAM_BOT_USERNAME=my_bot TELEGRAM_BOT_TOKEN=123456:ABCDEF... cline connect telegram
TELEGRAM_BOT_TOKEN=123456:ABCDEF... cline connect telegram
# Override the workspace and model used for Telegram sessions.
cline connect telegram -m my_bot -k "$TELEGRAM_BOT_TOKEN" --cwd /path/to/repo --provider cline --model openai/gpt-5.3-codex
cline connect telegram -k "$TELEGRAM_BOT_TOKEN" --cwd /path/to/repo --provider cline --model openai/gpt-5.3-codex
# Disable tools for untrusted Telegram surfaces.
cline connect telegram -m my_bot -k "$TELEGRAM_BOT_TOKEN" --no-tools
cline connect telegram -k "$TELEGRAM_BOT_TOKEN" --no-tools
# Stop Telegram connector processes and sessions.
cline connect --stop telegram
@@ -69,7 +71,7 @@ Tools are enabled by default for Telegram sessions. That means anyone who can su
Use `--no-tools` when the Telegram surface is not trusted:
```bash
cline connect telegram -m my_bot -k "$TELEGRAM_BOT_TOKEN" --no-tools
cline connect telegram -k "$TELEGRAM_BOT_TOKEN" --no-tools
```
When the connector starts with `--no-tools`, chat commands such as `/tools on` and `/yolo on` cannot re-enable tools for that connector run.
@@ -109,6 +111,11 @@ cline schedule create "Daily summary" \
--delivery-thread telegram:123456789
```
`--delivery-bot` is still supported after token-only connector setup. Use
the Telegram bot username shown by `/whereami` as `deliveryUserName` when you
need to target one specific Telegram connector, or omit the flag when the
schedule does not need to be restricted to a specific bot.
The connector must be running when the scheduled result is delivered, and the target thread must have an existing thread binding.
## Limitations
@@ -1,5 +1,8 @@
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import type { ConnectTelegramOptions } from "@cline/shared";
import { describe, expect, it } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import { __test__, telegramConnector } from "./telegram";
const parseTelegramArgs = (rawArgs: string[]): ConnectTelegramOptions =>
@@ -9,6 +12,28 @@ const parseTelegramArgs = (rawArgs: string[]): ConnectTelegramOptions =>
}
).parseArgs(rawArgs);
const originalClineDataDir = process.env.CLINE_DATA_DIR;
const tempDataDirs: string[] = [];
function useTempClineDataDir(): string {
const dataDir = mkdtempSync(join(tmpdir(), "cline-telegram-test-"));
tempDataDirs.push(dataDir);
process.env.CLINE_DATA_DIR = dataDir;
return dataDir;
}
afterEach(() => {
vi.unstubAllGlobals();
if (originalClineDataDir === undefined) {
delete process.env.CLINE_DATA_DIR;
} else {
process.env.CLINE_DATA_DIR = originalClineDataDir;
}
for (const dir of tempDataDirs.splice(0)) {
rmSync(dir, { recursive: true, force: true });
}
});
describe("telegramConnector", () => {
it("honors --no-tools", () => {
const options = parseTelegramArgs([
@@ -36,6 +61,129 @@ describe("telegramConnector", () => {
expect(options.enableTools).toBe(true);
});
it("does not require the bot username", () => {
const options = parseTelegramArgs([
"--bot-token",
"123:test",
"--cwd",
"/tmp/work",
]);
expect(options.botUsername).toBeUndefined();
expect(options.botToken).toBe("123:test");
});
it("normalizes an explicit bot username", () => {
const options = parseTelegramArgs([
"--bot-username",
" @test_bot ",
"--bot-token",
"123:test",
"--cwd",
"/tmp/work",
]);
expect(options.botUsername).toBe("test_bot");
});
it("does not call getMe when the token-only connector is already running", async () => {
const dataDir = useTempClineDataDir();
const connectorDir = join(dataDir, "connectors", "telegram");
mkdirSync(connectorDir, { recursive: true });
writeFileSync(
join(connectorDir, "resolved_bot.json"),
JSON.stringify({
botUsername: "resolved_bot",
botId: "123",
pid: process.pid,
rpcAddress: "127.0.0.1:54321",
startedAt: new Date().toISOString(),
}),
);
const fetchImpl = vi.fn(async () => {
throw new Error("unexpected getMe call");
});
vi.stubGlobal("fetch", fetchImpl);
const output: string[] = [];
const errors: string[] = [];
await expect(
telegramConnector.run(["--bot-token", "123:test", "--cwd", "/tmp/work"], {
writeln: (text = "") => output.push(text),
writeErr: (text) => errors.push(text),
}),
).resolves.toBe(0);
expect(fetchImpl).not.toHaveBeenCalled();
expect(errors).toEqual([]);
expect(output).toEqual([
`[telegram] connector already running pid=${process.pid} rpc=127.0.0.1:54321`,
]);
});
});
describe("telegram bot username resolution", () => {
it("reads the public Telegram bot id from a token", () => {
expect(__test__.readTelegramBotId("123456:secret")).toBe("123456");
expect(__test__.readTelegramBotId("not-a-token")).toBeUndefined();
});
it("uses the configured username without calling Telegram", async () => {
const fetchImpl = vi.fn(async () => {
throw new Error("unexpected fetch");
});
await expect(
__test__.resolveTelegramBotUsername(
{
botToken: "123:test",
botUsername: "@configured_bot",
cwd: "/tmp/work",
mode: "act",
interactive: true,
enableTools: true,
rpcAddress: "127.0.0.1:0",
},
fetchImpl,
),
).resolves.toBe("configured_bot");
expect(fetchImpl).not.toHaveBeenCalled();
});
it("fetches the username from Telegram getMe when omitted", async () => {
const fetchImpl = vi.fn(async () => {
return new Response(
JSON.stringify({
ok: true,
result: { username: "resolved_bot" },
}),
);
});
await expect(
__test__.fetchTelegramBotUsername("123:test", fetchImpl),
).resolves.toBe("resolved_bot");
expect(fetchImpl).toHaveBeenCalledWith(
"https://api.telegram.org/bot123:test/getMe",
);
});
it("surfaces Telegram getMe failures", async () => {
const fetchImpl = vi.fn(async () => {
return new Response(
JSON.stringify({
ok: false,
description: "Unauthorized",
}),
{ status: 401, statusText: "Unauthorized" },
);
});
await expect(
__test__.fetchTelegramBotUsername("bad-token", fetchImpl),
).rejects.toThrow("Telegram getMe failed");
});
});
describe("telegram participant resolution", () => {
+145 -10
View File
@@ -63,13 +63,86 @@ import { postTelegramFormattedReply } from "./telegram-format";
const TELEGRAM_SYSTEM_RULES = getConnectorSystemRules("Telegram");
const TELEGRAM_FIRST_CONTACT_MESSAGE = getConnectorFirstContactMessage();
const TELEGRAM_API_BASE = "https://api.telegram.org";
type TelegramThreadState = ConnectorThreadState;
type ResolvedTelegramOptions = ConnectTelegramOptions & { botUsername: string };
type TelegramGetMeResponse = {
ok?: boolean;
description?: string;
result?: {
username?: string;
};
};
type FetchLike = (input: string | URL, init?: RequestInit) => Promise<Response>;
function truncateText(value: string, maxLength = 160): string {
return truncateConnectorText(value, maxLength);
}
function normalizeTelegramBotUsername(value: string): string {
return value.trim().replace(/^@+/, "");
}
function readTelegramBotId(botToken: string): string | undefined {
const [botId] = botToken.trim().split(":", 1);
return /^\d+$/.test(botId) ? botId : undefined;
}
function describeTelegramGetMeFailure(
response: Response,
body: string,
parsed: TelegramGetMeResponse | undefined,
): string {
const detail = parsed?.description || body.trim().slice(0, 240);
return detail
? `Telegram getMe failed (${response.status} ${response.statusText}): ${detail}`
: `Telegram getMe failed (${response.status} ${response.statusText})`;
}
async function readTelegramGetMeResponse(
response: Response,
): Promise<TelegramGetMeResponse> {
const text = await response.text();
let parsed: TelegramGetMeResponse;
try {
parsed = JSON.parse(text) as TelegramGetMeResponse;
} catch {
throw new Error(describeTelegramGetMeFailure(response, text, undefined));
}
if (!response.ok || parsed.ok !== true) {
throw new Error(describeTelegramGetMeFailure(response, text, parsed));
}
return parsed;
}
async function fetchTelegramBotUsername(
botToken: string,
fetchImpl: FetchLike = fetch,
apiBaseUrl = TELEGRAM_API_BASE,
): Promise<string> {
const response = await fetchImpl(`${apiBaseUrl}/bot${botToken}/getMe`);
const payload = await readTelegramGetMeResponse(response);
const username = normalizeTelegramBotUsername(payload.result?.username ?? "");
if (!username) {
throw new Error(
"Telegram getMe did not return a bot username; pass --bot-username explicitly",
);
}
return username;
}
async function resolveTelegramBotUsername(
options: ConnectTelegramOptions,
fetchImpl?: FetchLike,
): Promise<string> {
const configured = normalizeTelegramBotUsername(options.botUsername ?? "");
if (configured) {
return configured;
}
return fetchTelegramBotUsername(options.botToken, fetchImpl);
}
async function stopSessionsForBot(
state: TelegramConnectorState,
): Promise<number> {
@@ -331,8 +404,11 @@ class TelegramConnector extends ConnectorBase<
protected override createCommand(): Command {
return super
.createCommand()
.usage("-m <TELEGRAM_BOT_USERNAME> -k <TELEGRAM_BOT_TOKEN> [options]")
.option("-m, --bot-username <name>", "Telegram bot username")
.usage("-k <TELEGRAM_BOT_TOKEN> [options]")
.option(
"-m, --bot-username <name>",
"Telegram bot username; fetched from token if omitted",
)
.option("-k, --bot-token <token>", "Telegram bot token")
.option("--provider <id>", "Provider override")
.option("--model <id>", "Model override")
@@ -358,6 +434,7 @@ class TelegramConnector extends ConnectorBase<
"Notes:",
" - Without -i, the connector is launched in the background.",
" - Tools are enabled by default for Telegram sessions.",
" - Bot username is discovered from the Telegram bot token when omitted.",
" - Provider/model default to the CLI's last-used provider settings.",
].join("\n"),
);
@@ -379,18 +456,18 @@ class TelegramConnector extends ConnectorBase<
hookCommand?: string;
}>();
const botUsername =
opts.botUsername?.trim() || process.env.TELEGRAM_BOT_USERNAME?.trim();
normalizeTelegramBotUsername(opts.botUsername ?? "") ||
normalizeTelegramBotUsername(
process.env.TELEGRAM_BOT_USERNAME?.trim() ?? "",
);
const botToken =
opts.botToken?.trim() || process.env.TELEGRAM_BOT_TOKEN?.trim();
if (!botUsername) {
throw new Error("connect telegram requires -m/--bot-username <name>");
}
if (!botToken) {
throw new Error("connect telegram requires -k/--bot-token <token>");
}
return {
botToken,
botUsername,
...(botUsername ? { botUsername } : {}),
cwd: opts.cwd || process.cwd(),
model: opts.model,
provider: opts.provider,
@@ -445,6 +522,28 @@ class TelegramConnector extends ConnectorBase<
this.writeStateFile(statePath, state);
}
private findRunningConnectorStateByBotId(
botId: string | undefined,
): TelegramConnectorState | undefined {
if (!botId) {
return undefined;
}
for (const statePath of this.listConnectorStatePaths()) {
const state = this.readConnectorState(statePath);
if (!state) {
continue;
}
if (!isProcessRunning(state.pid)) {
this.removeStateFile(statePath);
continue;
}
if (state.botId === botId) {
return state;
}
}
return undefined;
}
private async stopTelegramConnectorInstance(
statePath: string,
io: ConnectIo,
@@ -475,10 +574,39 @@ class TelegramConnector extends ConnectorBase<
}
protected override async runWithOptions(
options: ConnectTelegramOptions,
inputOptions: ConnectTelegramOptions,
rawArgs: string[],
io: ConnectIo,
): Promise<number> {
if (
!inputOptions.botUsername &&
!inputOptions.interactive &&
process.env.CLINE_TELEGRAM_CONNECT_CHILD !== "1"
) {
const runningState = this.findRunningConnectorStateByBotId(
readTelegramBotId(inputOptions.botToken),
);
if (runningState) {
io.writeln(
`[telegram] connector already running pid=${runningState.pid} rpc=${runningState.rpcAddress}`,
);
return 0;
}
}
let resolvedBotUsername: string;
try {
resolvedBotUsername = await resolveTelegramBotUsername(inputOptions);
} catch (error) {
io.writeErr(error instanceof Error ? error.message : String(error));
return 1;
}
const options: ResolvedTelegramOptions = {
...inputOptions,
botUsername: resolvedBotUsername,
};
const backgroundArgs = inputOptions.botUsername
? rawArgs
: [...rawArgs, "--bot-username", resolvedBotUsername];
const statePath = this.resolveConnectorStatePath(options.botUsername);
const bindingsPath = this.resolveBindingsPath(options.botUsername);
this.removeStaleState(
@@ -488,7 +616,7 @@ class TelegramConnector extends ConnectorBase<
);
if (
await this.maybeRunInBackground({
rawArgs,
rawArgs: backgroundArgs,
io,
interactive: options.interactive,
childEnvVar: "CLINE_TELEGRAM_CONNECT_CHILD",
@@ -574,6 +702,7 @@ class TelegramConnector extends ConnectorBase<
await client.connect();
this.writeConnectorState(statePath, {
botUsername: options.botUsername,
botId: readTelegramBotId(options.botToken),
pid: process.pid,
rpcAddress,
startedAt: new Date().toISOString(),
@@ -847,7 +976,10 @@ class TelegramConnector extends ConnectorBase<
requestStop("rpc_server_shutting_down");
return;
}
if (event.eventType !== "schedule.execution.completed") {
if (
event.eventType !== "schedule.execution.completed" &&
event.eventType !== "schedule.execution.failed"
) {
return;
}
const scheduleId =
@@ -957,6 +1089,9 @@ export const telegramConnector: ConnectCommandDefinition =
new TelegramConnector();
export const __test__ = {
fetchTelegramBotUsername,
readTelegramBotId,
resolveTelegramBotUsername,
resolveTelegramParticipant,
findBindingForThread: (
bindings: ConnectorBindingStore<TelegramThreadState>,
@@ -786,7 +786,10 @@ class WhatsAppConnector extends ConnectorBase<
requestStop("rpc_server_shutting_down");
return;
}
if (event.eventType !== "schedule.execution.completed") {
if (
event.eventType !== "schedule.execution.completed" &&
event.eventType !== "schedule.execution.failed"
) {
return;
}
const scheduleId =
+21
View File
@@ -657,6 +657,27 @@ describe("runCli lightweight command dispatch", () => {
expect(runtimeMocks.runInteractive).not.toHaveBeenCalled();
});
it("treats dash-prefixed positional text after -- as a prompt", async () => {
forcePromptModeInput();
process.argv = [
"bun",
"src/index.ts",
"--",
"- You are given a PyTorch state dictionary.",
];
const { runCli } = await import("./main");
await expect(runCli()).resolves.toBeUndefined();
expect(runtimeMocks.runAgent).toHaveBeenCalledTimes(1);
expect(runtimeMocks.runAgent).toHaveBeenCalledWith(
"- You are given a PyTorch state dictionary.",
expect.any(Object),
expect.anything(),
);
expect(runtimeMocks.runInteractive).not.toHaveBeenCalled();
});
it("applies --auto-approve as a runtime policy without changing the config default", async () => {
process.argv = ["bun", "src/index.ts", "--auto-approve", "false"];
+5 -2
View File
@@ -245,8 +245,11 @@ export async function runCli(): Promise<void> {
const pluginInstallCmd = pluginCmd
.command("install")
.alias("i")
.description("Install a Cline Plugin from npm, git, or a local path")
.argument("<source>", "npm package, git URL, or local plugin path")
.description("Install a Cline Plugin from npm, git, URL, or a local path")
.argument(
"<source>",
"npm package, git URL, plugin file URL, or local plugin path",
)
.option("--npm", "Treat source as an npm package")
.option("--git", "Treat source as a git repository")
.option("--force", "Replace an existing install for the same source")
@@ -42,6 +42,7 @@ function makeRuntime(): InteractiveChatCommandRuntime {
return {
forkCurrentSession: vi.fn(async () => undefined),
getActiveSessionId: vi.fn(() => "session-1"),
resetForNewSession: vi.fn(async () => {}),
restartEmpty: vi.fn(async () => {}),
};
}
@@ -101,6 +102,34 @@ describe("runInteractiveChatCommand", () => {
expect(runtime.restartEmpty).toHaveBeenCalledOnce();
});
it("resets slash new without eagerly restarting the runtime", async () => {
const config = makeConfig();
const runtime = makeRuntime();
const result = await runInteractiveChatCommand({
prompt: "/new",
enabled: true,
config,
host: chatCommandHost,
chatCommandState: makeState(config),
autoApproveAllRef: { current: false },
setInteractiveAutoApprove: () => {},
sessionRuntime: runtime,
stop: () => {},
});
expect(result).toEqual({
handled: true,
turnResult: {
usage: { inputTokens: 0, outputTokens: 0 },
iterations: 0,
commandOutput: "Started a fresh session.",
},
});
expect(runtime.resetForNewSession).toHaveBeenCalledOnce();
expect(runtime.restartEmpty).not.toHaveBeenCalled();
});
it("applies chat command state updates and returns command output", async () => {
const config = makeConfig();
const runtime = makeRuntime();
@@ -18,7 +18,10 @@ type AutoApproveRef = {
export type InteractiveChatCommandRuntime = Pick<
ReturnType<typeof createInteractiveSessionRuntime>,
"forkCurrentSession" | "getActiveSessionId" | "restartEmpty"
| "forkCurrentSession"
| "getActiveSessionId"
| "resetForNewSession"
| "restartEmpty"
>;
export type InteractiveChatCommandResult =
@@ -79,7 +82,7 @@ export async function runInteractiveChatCommand(input: {
commandOutput = text;
},
reset: async () => {
await input.sessionRuntime.restartEmpty();
await input.sessionRuntime.resetForNewSession();
},
stop: async () => {
input.stop();
@@ -3,6 +3,10 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
import type { UserInstructionConfigService } from "@cline/core";
import { afterEach, describe, expect, it } from "vitest";
import {
buildSlashCommandRegistry,
expandUserCommandPrompt,
} from "../../tui/commands/slash-command-registry";
import {
applyPluginFailures,
type InteractiveConfigItem,
@@ -91,6 +95,19 @@ Use this skill.`,
calls.push(`refreshType:${type}`);
refreshed = true;
},
listRuntimeCommands() {
calls.push("listRuntimeCommands");
return refreshed
? []
: [
{
name: "skill-one",
instructions: "Use this skill.",
description: "Skill one",
kind: "skill",
},
];
},
listRecords(type: string) {
calls.push(`listRecords:${type}`);
if (type !== "skill") {
@@ -130,12 +147,97 @@ Use this skill.`,
expect(written).toContain("disabled: true");
expect(data?.skills[0]?.enabled).toBe(false);
expect(
data?.workflowSlashCommands.map((command) => command.name),
).not.toContain("skill-one");
expect(calls).toContain("refreshType:skill");
expect(calls.lastIndexOf("listRecords:skill")).toBeGreaterThan(
calls.indexOf("refreshType:skill"),
);
});
it("returns refreshed slash commands so disabled skills stop expanding before submit", async () => {
const tempRoot = await mkdtemp(join(tmpdir(), "cli-config-data-"));
tempRoots.push(tempRoot);
const skillPath = join(tempRoot, "SKILL.md");
await writeFile(
skillPath,
`---
name: find-skills
---
Find installable skills.`,
);
let refreshed = false;
const userInstructionService = {
async refreshType() {
refreshed = true;
},
listRuntimeCommands() {
return refreshed
? []
: [
{
name: "find-skills",
instructions: "Find installable skills.",
description: "Find skills",
kind: "skill",
},
];
},
listRecords(type: string) {
if (type !== "skill") {
return [];
}
return [
{
id: "find-skills",
type: "skill",
filePath: skillPath,
item: {
name: "find-skills",
disabled: refreshed,
description: "Find skills",
instructions: "Find installable skills.",
frontmatter: {},
},
},
];
},
} as unknown as UserInstructionConfigService;
const loader = createInteractiveConfigDataLoader({
config: createConfig(tempRoot),
userInstructionService,
});
const initialData = await loader.loadConfigData();
const initialRegistry = buildSlashCommandRegistry({
workflowSlashCommands: initialData.workflowSlashCommands,
});
expect(
expandUserCommandPrompt("/find-skills what can u do?", initialRegistry),
).toContain("<user_command");
const nextData = await loader.onToggleConfigItem({
id: "find-skills",
name: "find-skills",
path: skillPath,
enabled: true,
source: "workspace",
kind: "skill",
});
const refreshedRegistry = buildSlashCommandRegistry({
workflowSlashCommands: nextData?.workflowSlashCommands,
});
expect(
nextData?.workflowSlashCommands.map((command) => command.name),
).not.toContain("find-skills");
expect(
expandUserCommandPrompt("/find-skills what can u do?", refreshedRegistry),
).toBe("/find-skills what can u do?");
});
it("keeps plugin tool toggle behavior", async () => {
const tempRoot = await mkdtemp(join(tmpdir(), "cli-config-data-"));
tempRoots.push(tempRoot);
@@ -163,7 +265,7 @@ Use this skill.`,
) as { disabledTools?: string[] };
expect(settings.disabledTools).toEqual(["plugin-tool"]);
expect(data).toBeDefined();
expect(data).toBeUndefined();
});
it("can skip plugin tool imports for fast settings open", async () => {
@@ -341,13 +443,15 @@ Use this skill.`,
}
const nextData = await loader.onToggleConfigItem(plugin);
const refreshedData = await loader.loadConfigData();
const settings = JSON.parse(
await readFile(process.env.CLINE_GLOBAL_SETTINGS_PATH, "utf8"),
) as { disabledPlugins?: string[] };
expect(settings.disabledPlugins).toBeUndefined();
expect(nextData).toBeUndefined();
expect(
nextData?.plugins.find((item) => item.path === pluginPath)?.enabled,
refreshedData.plugins.find((item) => item.path === pluginPath)?.enabled,
).toBe(true);
});
@@ -1,6 +1,7 @@
import {
createCoreSettingsService,
setDisabledPlugin,
setDisabledTools,
type UserInstructionConfigService,
} from "@cline/core";
import {
@@ -57,7 +58,7 @@ export function createInteractiveConfigDataLoader(input: {
if (item.kind === "plugin" && typeof item.enabled === "boolean") {
setDisabledPlugin(item.path, item.enabled);
return await loadConfigData(options);
return undefined;
}
if (item.kind === "mcp" && typeof item.enabled === "boolean") {
@@ -87,18 +88,22 @@ export function createInteractiveConfigDataLoader(input: {
? item.toolNames
: [item.name];
const toolNames = [...new Set(rawToolNames.filter(Boolean))];
if (typeof item.enabled === "boolean") {
setDisabledTools(toolNames, item.enabled);
return undefined;
}
for (const name of toolNames) {
await settings.toggle({
type: "tools",
name,
enabled: typeof item.enabled === "boolean" ? !item.enabled : undefined,
cwd: input.config.cwd,
workspaceRoot: workspaceRoot(),
userInstructionService: input.userInstructionService,
availabilityContext: availabilityContext(),
});
}
return await loadConfigData(options);
return undefined;
};
return {
@@ -0,0 +1,234 @@
import type {
AgentEvent,
ProviderSettingsManager,
TeamEvent,
ToolApprovalRequest,
ToolApprovalResult,
} from "@cline/core";
import type { AgentTool } from "@cline/shared";
import { beforeEach, describe, expect, it, vi } from "vitest";
import type { ChatCommandState } from "../../utils/chat-commands";
import type { Config } from "../../utils/types";
const {
mockCreateCliCore,
mockCreateRuntimeHooks,
mockLoadInteractiveResumeMessages,
mockSetActiveCliSession,
} = vi.hoisted(() => ({
mockCreateCliCore: vi.fn(),
mockCreateRuntimeHooks: vi.fn(),
mockLoadInteractiveResumeMessages: vi.fn(),
mockSetActiveCliSession: vi.fn(),
}));
vi.mock("../../session/session", () => ({
createCliCore: mockCreateCliCore,
}));
vi.mock("../../utils/hooks", () => ({
createRuntimeHooks: mockCreateRuntimeHooks,
}));
vi.mock("../../utils/output", () => ({
setActiveCliSession: mockSetActiveCliSession,
}));
vi.mock("../../utils/resume", () => ({
loadInteractiveResumeMessages: mockLoadInteractiveResumeMessages,
}));
vi.mock("../../utils/approval", () => ({
submitAndExitInTerminal: vi.fn(),
}));
vi.mock("../active-runtime", () => ({
markAbortInProgress: vi.fn(),
}));
vi.mock("../session-events", () => ({
subscribeToAgentEvents: vi.fn(() => vi.fn()),
subscribeToPendingPromptEvents: vi.fn(() => vi.fn()),
}));
import { createInteractiveSessionRuntime } from "./session-runtime";
function makeConfig(): Config {
return {
apiKey: "",
providerId: "cline",
modelId: "openai/gpt-5.3-codex",
verbose: false,
sandbox: false,
thinking: false,
outputMode: "text",
mode: "act",
systemPrompt: "",
enableTools: true,
enableSpawnAgent: true,
enableAgentTeams: false,
defaultToolAutoApprove: false,
toolPolicies: {},
cwd: "/tmp/work",
workspaceRoot: "/tmp/work",
};
}
function makeChatCommandState(config: Config): ChatCommandState {
return {
enableTools: config.enableTools,
autoApproveTools: config.defaultToolAutoApprove,
cwd: config.cwd,
workspaceRoot: config.workspaceRoot?.trim() || config.cwd,
};
}
function makeSwitchToActModeTool(): AgentTool {
return {
name: "switch_to_act_mode",
description: "Switch to act mode",
inputSchema: { type: "object", properties: {} },
execute: () => ({ ok: true }),
};
}
function makeManager() {
let startCount = 0;
const start = vi.fn(async (_input?: unknown) => {
startCount += 1;
const sessionId = `session-${startCount}`;
return {
sessionId,
manifest: {
session_id: sessionId,
},
};
});
return {
start,
stop: vi.fn(async () => {}),
send: vi.fn(),
getAccumulatedUsage: vi.fn(),
abort: vi.fn(),
dispose: vi.fn(),
get: vi.fn(),
readMessages: vi.fn(async () => []),
readTranscript: vi.fn(),
ingestHookEvent: vi.fn(),
subscribe: vi.fn(),
updateSessionModel: vi.fn(),
pendingPrompts: {
update: vi.fn(),
},
restore: vi.fn(),
};
}
function makeRuntime(
manager: ReturnType<typeof makeManager>,
options: { resumeSessionId?: string } = {},
) {
mockCreateCliCore.mockResolvedValue(manager);
const config = makeConfig();
return createInteractiveSessionRuntime({
config,
providerSettingsManager: {} as ProviderSettingsManager,
resumeSessionId: options.resumeSessionId,
chatCommandState: makeChatCommandState(config),
requestToolApproval: async (
_request: ToolApprovalRequest,
): Promise<ToolApprovalResult> => ({ approved: true }),
askQuestionRef: { current: null },
resolveMistakeLimitDecision: undefined,
switchToActModeTool: makeSwitchToActModeTool(),
onAgentEvent: (_event: AgentEvent) => {},
onTeamEvent: (_event: TeamEvent) => {},
onPendingPrompts: () => {},
onPendingPromptSubmitted: () => {},
});
}
describe("createInteractiveSessionRuntime", () => {
beforeEach(() => {
vi.clearAllMocks();
mockCreateRuntimeHooks.mockReturnValue({
hooks: undefined,
shutdown: vi.fn(async () => {}),
});
mockLoadInteractiveResumeMessages.mockResolvedValue([]);
});
it("defers creating the replacement session after a new-session reset", async () => {
const manager = makeManager();
const runtime = makeRuntime(manager);
await runtime.ensureReady();
expect(manager.start).toHaveBeenCalledOnce();
expect(runtime.getActiveSessionId()).toBe("session-1");
await runtime.resetForNewSession();
expect(manager.stop).toHaveBeenCalledWith("session-1");
expect(manager.start).toHaveBeenCalledOnce();
expect(runtime.getActiveSessionId()).toBe("");
expect(mockSetActiveCliSession).toHaveBeenLastCalledWith(undefined);
await runtime.ensureReady();
expect(manager.start).toHaveBeenCalledTimes(2);
expect(runtime.getActiveSessionId()).toBe("session-2");
});
it("starts fresh after resetting an initially resumed session", async () => {
const manager = makeManager();
const runtime = makeRuntime(manager, {
resumeSessionId: "resumed-session",
});
await runtime.ensureReady();
expect(mockLoadInteractiveResumeMessages).toHaveBeenNthCalledWith(
1,
manager,
"resumed-session",
);
expect(manager.start).toHaveBeenNthCalledWith(
1,
expect.objectContaining({
config: expect.objectContaining({
sessionId: "resumed-session",
}),
}),
);
await runtime.resetForNewSession();
await runtime.ensureReady();
expect(mockLoadInteractiveResumeMessages).toHaveBeenNthCalledWith(
2,
manager,
undefined,
);
expect(manager.start).toHaveBeenCalledTimes(2);
expect(manager.start).toHaveBeenNthCalledWith(
2,
expect.objectContaining({
config: expect.not.objectContaining({
sessionId: "resumed-session",
}),
}),
);
});
it("keeps explicit empty restarts eager for config-driven restarts", async () => {
const manager = makeManager();
const runtime = makeRuntime(manager);
await runtime.ensureReady();
await runtime.restartEmpty();
expect(manager.stop).toHaveBeenCalledWith("session-1");
expect(manager.start).toHaveBeenCalledTimes(2);
expect(runtime.getActiveSessionId()).toBe("session-2");
});
});
@@ -74,8 +74,16 @@ export function createInteractiveSessionRuntime(input: {
let shutdownRequested = false;
let activeSessionId = "";
let abortRequested = false;
// A reset can happen while an earlier manager.start() is still in flight.
// Bump this before resets and restarts so stale starts cannot become active.
let sessionStartGeneration = 0;
const initialResumeSessionId = input.resumeSessionId?.trim() || undefined;
let pendingResumeSessionId = input.resumeSessionId?.trim() || undefined;
const clearActiveSession = (): void => {
activeSessionId = "";
setActiveCliSession(undefined);
};
const applyStartedSession = (started: StartedSession): void => {
setActiveCliSession({
@@ -155,6 +163,7 @@ export function createInteractiveSessionRuntime(input: {
initial: Message[] = [],
sessionMetadata?: Record<string, unknown>,
): Promise<void> => {
const generation = sessionStartGeneration;
const manager = await ensureSessionManager();
const started = await manager.start({
source: SessionSource.CLI,
@@ -168,6 +177,10 @@ export function createInteractiveSessionRuntime(input: {
onTeamRestored: () => {},
},
});
if (generation !== sessionStartGeneration) {
await manager.stop(started.sessionId).catch(() => {});
return;
}
applyStartedSession(started);
};
@@ -175,6 +188,7 @@ export function createInteractiveSessionRuntime(input: {
resumeId: string,
initial: Message[] | undefined,
): Promise<void> => {
const generation = sessionStartGeneration;
const manager = await ensureSessionManager();
const started = await manager.start({
source: SessionSource.CLI,
@@ -190,24 +204,35 @@ export function createInteractiveSessionRuntime(input: {
onTeamRestored: () => {},
},
});
if (generation !== sessionStartGeneration) {
await manager.stop(started.sessionId).catch(() => {});
return;
}
applyStartedSession(started);
};
const ensureReady = async (): Promise<void> => {
if (activeSessionId) {
return;
}
if (startupPromise) {
return await startupPromise;
}
startupPromise = (async () => {
const manager = await ensureSessionManager();
const resumeSessionId = pendingResumeSessionId;
const initialMessages = await loadInteractiveResumeMessages(
manager,
input.resumeSessionId,
resumeSessionId,
);
if (shutdownRequested) {
return;
}
if (initialResumeSessionId) {
await startResumedSession(initialResumeSessionId, initialMessages);
if (resumeSessionId) {
await startResumedSession(resumeSessionId, initialMessages);
if (pendingResumeSessionId === resumeSessionId) {
pendingResumeSessionId = undefined;
}
} else {
await startFreshSession(initialMessages);
}
@@ -226,8 +251,9 @@ export function createInteractiveSessionRuntime(input: {
};
const stopCurrentSession = async (): Promise<void> => {
if (sessionManager && activeSessionId) {
await sessionManager.stop(activeSessionId);
const sessionId = activeSessionId;
if (sessionManager && sessionId) {
await sessionManager.stop(sessionId);
}
};
@@ -262,7 +288,12 @@ export function createInteractiveSessionRuntime(input: {
messages: Message[],
sessionMetadata?: Record<string, unknown>,
): Promise<void> => {
sessionStartGeneration += 1;
pendingResumeSessionId = undefined;
startupPromise = undefined;
startupError = undefined;
await stopCurrentSession();
clearActiveSession();
await startFreshSession(messages, sessionMetadata);
};
@@ -275,6 +306,19 @@ export function createInteractiveSessionRuntime(input: {
await restartWithMessages([]);
};
const resetForNewSession = async (): Promise<void> => {
sessionStartGeneration += 1;
pendingResumeSessionId = undefined;
startupPromise = undefined;
startupError = undefined;
const manager = sessionManager;
const sessionId = activeSessionId;
clearActiveSession();
if (manager && sessionId) {
await manager.stop(sessionId);
}
};
const applyMode = async (mode: "plan" | "act"): Promise<void> => {
await applyInteractiveModeConfig({
config: input.config,
@@ -537,6 +581,7 @@ export function createInteractiveSessionRuntime(input: {
getAccumulatedUsage,
readCurrentMessages,
restartEmpty,
resetForNewSession,
restartWithMessages,
restartWithCurrentMessages,
resumeSession,
@@ -585,6 +585,9 @@ export async function runInteractive(
}
await applyModeChange(mode);
},
onNewSession: async () => {
await sessionRuntime.resetForNewSession();
},
onModelChange: async () => {
await sessionRuntime.ensureReady();
const existing = providerSettingsManager.getProviderSettings(
@@ -28,7 +28,7 @@ test.describe("cline --model (interactive mode, flag ignored)", () => {
test("starts interactive mode", async ({ terminal }) => {
await waitForChatReady(terminal);
await expectVisible(terminal, "GPT-5.3-Codex");
await expectVisible(terminal, "GPT-5.3 Codex");
});
});
@@ -166,6 +166,32 @@ describe("slash command registry", () => {
expect(expandUserCommandPrompt("/settings", registry)).toBe("/settings");
});
it("does not expand commands omitted from a refreshed user-command registry", () => {
const staleRegistry = buildSlashCommandRegistry({
workflowSlashCommands: [
{
name: "find-skills",
instructions: "Find installable skills.",
description: "Find skills",
kind: "skill",
},
],
});
const refreshedRegistry = buildSlashCommandRegistry({
workflowSlashCommands: [],
});
expect(
expandUserCommandPrompt("/find-skills what can u do?", staleRegistry),
).toContain("<user_command");
expect(
resolveSlashCommand(refreshedRegistry, "find-skills"),
).toBeUndefined();
expect(
expandUserCommandPrompt("/find-skills what can u do?", refreshedRegistry),
).toBe("/find-skills what can u do?");
});
it("hides fork from autocomplete until a session has messages", () => {
const emptySessionRegistry = buildSlashCommandRegistry({ canFork: false });
const activeSessionRegistry = buildSlashCommandRegistry({ canFork: true });
@@ -11,6 +11,7 @@ import {
} from "../palette";
import type { ChatEntry } from "../types";
import { getSyntaxStyle } from "../utils/syntax-style";
import { isWarningToolError } from "../utils/tool-errors";
import {
parseApplyPatchInput,
parseAskQuestionInput,
@@ -212,6 +213,7 @@ function ToolCallView(props: {
defaultFg,
} = props;
const failed = result?.error != null;
const warningFailure = isWarningToolError(result?.error);
const params = formatToolParams(toolName, props.rawInput, inputSummary);
return (
@@ -220,6 +222,8 @@ function ToolCallView(props: {
<box width={2}>
{streaming ? (
<spinner name="dots" color="gray" />
) : warningFailure ? (
<text fg="yellow">!</text>
) : failed ? (
<text fg="red">x</text>
) : (
@@ -33,25 +33,35 @@ export function ExtDetailContent(
) {
return;
}
const previousItem = item;
setToggleError(undefined);
if (typeof item.enabled === "boolean") {
setItem({ ...item, enabled: !item.enabled });
}
try {
const nextData = await props.onToggleConfigItem(item, {
includePluginTools: false,
});
const nextItem = [
...(nextData?.workflows ?? []),
...(nextData?.rules ?? []),
...(nextData?.skills ?? []),
...(nextData?.hooks ?? []),
...(nextData?.agents ?? []),
...(nextData?.plugins ?? []),
...(nextData?.mcp ?? []),
...(nextData?.tools ?? []),
].find(
(candidate) => candidate.id === item.id && candidate.path === item.path,
);
setItem(nextItem ?? { ...item, enabled: !item.enabled });
if (nextData) {
const nextItem = [
...nextData.workflows,
...nextData.rules,
...nextData.skills,
...nextData.hooks,
...nextData.agents,
...nextData.plugins,
...nextData.mcp,
...nextData.tools,
].find(
(candidate) =>
candidate.id === item.id && candidate.path === item.path,
);
if (nextItem) {
setItem(nextItem);
}
}
} catch (error) {
setItem(previousItem);
const message = error instanceof Error ? error.message : String(error);
setToggleError(`Failed to update ${item.name}: ${message}`);
}
@@ -0,0 +1,18 @@
import type { DialogActions, DialogId } from "@opentui-ui/dialog/react";
export type LoadingDialogActions = Pick<DialogActions, "show" | "close">;
export async function withShownDialog<T>(
dialog: Pick<DialogActions, "close">,
show: () => DialogId,
run: () => Promise<T>,
): Promise<T> {
const loadingDialogId = show();
// Give OpenTUI a microtask to mount the loading dialog before work starts.
await Promise.resolve();
try {
return await run();
} finally {
dialog.close(loadingDialogId);
}
}
@@ -0,0 +1,66 @@
import type { DialogActions, DialogId } from "@opentui-ui/dialog/react";
import { describe, expect, it } from "vitest";
import { withShownDialog } from "./loading-dialog-lifecycle";
type LoadingDialogCall =
| {
name: "show";
}
| {
name: "close";
id: DialogId | undefined;
};
function createDialog(calls: LoadingDialogCall[]) {
return {
close: (id?: DialogId): DialogId | undefined => {
calls.push({ name: "close", id });
return id;
},
} satisfies Pick<DialogActions, "close">;
}
function showLoading(calls: LoadingDialogCall[]): DialogId {
calls.push({ name: "show" });
return "loading-dialog";
}
describe("withShownDialog", () => {
it("shows a loading dialog while work runs", async () => {
const calls: LoadingDialogCall[] = [];
const events: string[] = [];
const dialog = createDialog(calls);
const result = await withShownDialog(
dialog,
() => showLoading(calls),
async () => {
events.push("run");
return 42;
},
);
expect(result).toBe(42);
expect(events).toEqual(["run"]);
expect(calls.map((call) => call.name)).toEqual(["show", "close"]);
expect(calls[1]).toEqual({ name: "close", id: "loading-dialog" });
});
it("closes the loading dialog when work fails", async () => {
const calls: LoadingDialogCall[] = [];
const dialog = createDialog(calls);
await expect(
withShownDialog(
dialog,
() => showLoading(calls),
async () => {
throw new Error("failed");
},
),
).rejects.toThrow("failed");
expect(calls.map((call) => call.name)).toEqual(["show", "close"]);
expect(calls[1]).toEqual({ name: "close", id: "loading-dialog" });
});
});
@@ -0,0 +1,56 @@
// @jsxImportSource @opentui/react
import type {
DialogId,
DialogSize,
DialogStyle,
} from "@opentui-ui/dialog/react";
import "opentui-spinner/react";
import {
type LoadingDialogActions,
withShownDialog,
} from "./loading-dialog-lifecycle";
export interface LoadingDialogContentProps {
message: string;
}
export function LoadingDialogContent(props: LoadingDialogContentProps) {
return (
<box flexDirection="row" gap={1} paddingX={1}>
<spinner name="dots" color="gray" />
<text fg="gray">{props.message}</text>
</box>
);
}
export interface LoadingDialogOptions {
size?: DialogSize;
style?: DialogStyle;
}
export function showLoadingDialog(
dialog: LoadingDialogActions,
message: string,
options?: LoadingDialogOptions,
): DialogId {
return dialog.show({
size: options?.size ?? "small",
style: options?.style,
closeOnEscape: false,
closeOnClickOutside: false,
content: () => <LoadingDialogContent message={message} />,
});
}
export async function withLoadingDialog<T>(
dialog: LoadingDialogActions,
message: string,
run: () => Promise<T>,
options?: LoadingDialogOptions,
): Promise<T> {
return await withShownDialog(
dialog,
() => showLoadingDialog(dialog, message, options),
run,
);
}
@@ -23,13 +23,13 @@ import {
} from "../../../utils/codex-cli";
import { isOAuthProvider } from "../../../utils/provider-auth";
import { palette } from "../../palette";
import { getProviderSection } from "../../utils/provider-sections";
import {
getDefaultAwsRegion,
type ProviderConfigValues,
resolveProviderConfigAwsRegion,
updateProviderConfigValue,
type ProviderConfigValues,
} from "../../utils/provider-config-values";
import { getProviderSection } from "../../utils/provider-sections";
import {
getSearchableListRowsWindow,
type SearchableItem,
@@ -456,6 +456,7 @@ export function ProviderConfigInputContent(
return (
<box key={key} flexDirection="column">
<text fg="gray">{label}</text>
{requirement.note && <text fg="gray">{requirement.note}</text>}
<box
border
borderStyle="rounded"
@@ -465,9 +466,7 @@ export function ProviderConfigInputContent(
<input
value={values[key] ?? ""}
onInput={(v: string) =>
setValues((prev) =>
updateProviderConfigValue(prev, key, v),
)
setValues((prev) => updateProviderConfigValue(prev, key, v))
}
placeholder={placeholder}
flexGrow={1}
@@ -14,7 +14,7 @@ import {
shortenPath,
} from "../../utils/tool-parsing";
function formatApprovalParams(
export function formatApprovalParams(
toolName: string,
rawInput: unknown,
): React.ReactNode {
@@ -0,0 +1,332 @@
import { useKeyboard, useTerminalDimensions } from "@opentui/react";
import { useCallback, useRef, useState } from "react";
import { palette } from "../palette";
import type { RuntimeToolInteraction } from "../types";
import { formatApprovalParams } from "./dialogs/tool-approval";
export interface InlineToolResponseProps {
interaction: RuntimeToolInteraction;
accent: string;
inputBackground: string;
inputForeground: string;
inputPlaceholder: string;
onResolveToolApproval: (id: number, approved: boolean) => void;
onResolveAskQuestion: (id: number, answer: string | null) => void;
}
function isPrintableKey(name: string): boolean {
return name.length === 1 || name === "space";
}
function keyToText(name: string): string {
return name === "space" ? " " : name;
}
function Shell(
props: Pick<
InlineToolResponseProps,
"accent" | "inputBackground" | "inputForeground"
> & {
title: string;
children: React.ReactNode;
},
) {
const { height } = useTerminalDimensions();
const maxHeight = Math.max(7, Math.min(14, Math.floor(height * 0.38)));
return (
<box
flexDirection="column"
width="100%"
maxHeight={maxHeight}
backgroundColor={props.inputBackground}
paddingX={1}
paddingY={1}
gap={1}
>
<box flexDirection="row" gap={1}>
<text fg={palette.act}>{props.title}</text>
</box>
{props.children}
</box>
);
}
function ChoiceButton(props: {
label: string;
selected: boolean;
selectedFg?: string;
onPress: () => void;
}) {
return (
<box
paddingX={1}
backgroundColor={props.selected ? palette.selection : undefined}
onMouseDown={props.onPress}
>
<text
fg={
props.selected
? (props.selectedFg ?? palette.textOnSelection)
: undefined
}
>
{props.label}
</text>
</box>
);
}
function ToolApprovalResponse(
props: InlineToolResponseProps & {
interaction: Extract<RuntimeToolInteraction, { kind: "tool_approval" }>;
},
) {
const [selected, setSelected] = useState<"approve" | "deny">("approve");
const selectedRef = useRef(selected);
selectedRef.current = selected;
const request = props.interaction.request;
const interactionId = props.interaction.id;
const onResolveToolApproval = props.onResolveToolApproval;
const params = formatApprovalParams(request.toolName, request.input);
const resolve = useCallback(
(approved: boolean) => {
onResolveToolApproval(interactionId, approved);
},
[interactionId, onResolveToolApproval],
);
useKeyboard((key) => {
if (key.name === "y") {
resolve(true);
return;
}
if (key.name === "n" || key.name === "escape") {
resolve(false);
return;
}
if (key.name === "left" || key.name === "right" || key.name === "tab") {
setSelected((current) => (current === "approve" ? "deny" : "approve"));
return;
}
if (key.name === "return" || key.name === "enter") {
resolve(selectedRef.current === "approve");
}
});
return (
<Shell
title="Cline needs permission"
accent={props.accent}
inputBackground={props.inputBackground}
inputForeground={props.inputForeground}
>
<box flexDirection="column" gap={1}>
<text fg="yellow">Approve tool call?</text>
<text fg={props.accent} selectable>
{request.toolName}
</text>
{params && (
<box flexDirection="column" overflow="hidden">
{params}
</box>
)}
</box>
<box flexDirection="row" gap={1}>
<ChoiceButton
label="[y] Approve"
selected={selected === "approve"}
onPress={() => resolve(true)}
/>
<ChoiceButton
label="[n] Deny"
selected={selected === "deny"}
onPress={() => resolve(false)}
/>
</box>
</Shell>
);
}
function AskQuestionResponse(
props: InlineToolResponseProps & {
interaction: Extract<RuntimeToolInteraction, { kind: "ask_question" }>;
},
) {
const { interaction } = props;
const [selected, setSelected] = useState(0);
const [customValue, setCustomValue] = useState("");
const [customEmptyAttempted, setCustomEmptyAttempted] = useState(false);
const selectedRef = useRef(0);
const customValueRef = useRef("");
const interactionId = interaction.id;
const onResolveAskQuestion = props.onResolveAskQuestion;
const customIndex = interaction.options.length;
const isTyping = selected === customIndex;
const totalChoices = interaction.options.length + 1;
const selectIndex = useCallback(
(index: number) => {
selectedRef.current = index;
setSelected(index);
if (index !== customIndex) {
setCustomEmptyAttempted(false);
}
},
[customIndex],
);
const setCustomText = useCallback((value: string) => {
customValueRef.current = value;
setCustomValue(value);
if (value.trim()) {
setCustomEmptyAttempted(false);
}
}, []);
const resolveAnswer = useCallback(
(answer: string | null) => {
onResolveAskQuestion(interactionId, answer);
},
[interactionId, onResolveAskQuestion],
);
useKeyboard((key) => {
const typing = selectedRef.current === customIndex;
if (key.name === "escape") {
if (typing && customValueRef.current) {
setCustomText("");
return;
}
resolveAnswer(null);
return;
}
if (typing && key.name === "backspace") {
setCustomText(customValueRef.current.slice(0, -1));
return;
}
if (typing && key.name === "delete") {
setCustomText("");
return;
}
if (key.name === "return" || key.name === "enter") {
if (typing) {
const answer = customValueRef.current.trim();
if (answer) {
resolveAnswer(answer);
return;
}
setCustomEmptyAttempted(true);
return;
}
resolveAnswer(interaction.options[selectedRef.current] ?? "");
return;
}
if (key.name === "up" || (key.ctrl && key.name === "p")) {
const next =
selectedRef.current <= 0 ? totalChoices - 1 : selectedRef.current - 1;
selectIndex(next);
return;
}
if (key.name === "down" || (key.ctrl && key.name === "n")) {
const next =
selectedRef.current >= totalChoices - 1 ? 0 : selectedRef.current + 1;
selectIndex(next);
return;
}
if (!typing && key.name >= "1" && key.name <= "9") {
const index = Number.parseInt(key.name, 10) - 1;
const option = interaction.options[index];
if (option) {
resolveAnswer(option);
return;
}
}
if (typing && !key.ctrl && !key.meta && isPrintableKey(key.name)) {
const value = keyToText(key.name);
setCustomText(`${customValueRef.current}${value}`);
return;
}
if (!key.ctrl && !key.meta && isPrintableKey(key.name)) {
const value = keyToText(key.name);
setCustomText(value);
selectIndex(customIndex);
}
});
return (
<Shell
title="Cline is asking a question"
accent={props.accent}
inputBackground={props.inputBackground}
inputForeground={props.inputForeground}
>
<text fg={props.inputForeground} selectable>
{interaction.question}
</text>
<box flexDirection="column">
{interaction.options.map((option, index) => {
const optionSelected = !isTyping && selected === index;
return (
<box
key={`${index.toString()}:${option}`}
paddingX={1}
flexDirection="row"
gap={1}
backgroundColor={optionSelected ? palette.selection : undefined}
onMouseDown={() => resolveAnswer(option)}
>
<text
fg={optionSelected ? palette.textOnSelection : "gray"}
flexShrink={0}
>
{optionSelected ? ">" : " "}
</text>
<text
fg={
optionSelected
? palette.textOnSelection
: props.inputForeground
}
>
{option}
</text>
</box>
);
})}
<box
paddingX={1}
flexDirection="row"
gap={1}
backgroundColor={isTyping ? palette.selection : undefined}
onMouseDown={() => selectIndex(customIndex)}
>
<text fg={isTyping ? palette.textOnSelection : "gray"} flexShrink={0}>
{isTyping ? ">" : " "}
</text>
{isTyping ? (
<text fg={palette.textOnSelection} flexGrow={1}>
{customValue
? `${customValue}|`
: customEmptyAttempted
? "Type a response first..."
: "Type a response..."}
</text>
) : (
<text fg={props.inputPlaceholder}>Type a response...</text>
)}
</box>
</box>
</Shell>
);
}
export function InlineToolResponse(props: InlineToolResponseProps) {
if (props.interaction.kind === "tool_approval") {
return <ToolApprovalResponse {...props} interaction={props.interaction} />;
}
return <AskQuestionResponse {...props} interaction={props.interaction} />;
}
@@ -3,6 +3,7 @@ import { useTerminalTheme } from "../hooks/use-terminal-background";
import { diffPalettes, palette, type TerminalTheme } from "../palette";
import { makeUnifiedDiff } from "../utils/diff";
import { getSyntaxStyle } from "../utils/syntax-style";
import { getToolErrorPresentation } from "../utils/tool-errors";
import {
detectLanguage,
extractFullOutputText,
@@ -292,13 +293,29 @@ function GenericOutput(props: { outputSummary: string; fullText?: string }) {
export function ToolOutput(props: ToolOutputProps) {
const { toolName, outputSummary, rawOutput, rawInput, error } = props;
const terminalTheme = useTerminalTheme();
const [errorExpanded, setErrorExpanded] = useState(false);
if (error) {
const presentation = getToolErrorPresentation(error);
const isWarning = presentation.severity === "warning";
const showDetail =
errorExpanded && presentation.detail !== presentation.summary.trim();
return (
<box paddingLeft={2}>
<text fg="red" selectable>
{" "} Error: {error}
<box
flexDirection="column"
paddingLeft={2}
onMouseDown={() => setErrorExpanded(!errorExpanded)}
>
<text fg={isWarning ? "yellow" : "red"} selectable>
{" "} {isWarning ? "!" : "Error:"} {presentation.summary}
</text>
{showDetail && (
<box paddingLeft={3}>
<text fg="gray" selectable>
{presentation.detail}
</text>
</box>
)}
</box>
);
}
@@ -218,23 +218,20 @@ export function SessionProvider(props: {
setLastTotalCost(0);
}, []);
const addUsageDelta = useCallback(
(usage: UsageDelta) => {
const nextTotalTokens = nextUsageTokenDisplay(0, usage);
if (nextTotalTokens > 0) {
setLastTotalTokens((prev) => nextUsageTokenDisplay(prev, usage));
}
const costDelta = usage.cost;
if (
typeof costDelta === "number" &&
Number.isFinite(costDelta) &&
costDelta > 0
) {
setLastTotalCost((prev) => prev + costDelta);
}
},
[],
);
const addUsageDelta = useCallback((usage: UsageDelta) => {
const nextTotalTokens = nextUsageTokenDisplay(0, usage);
if (nextTotalTokens > 0) {
setLastTotalTokens((prev) => nextUsageTokenDisplay(prev, usage));
}
const costDelta = usage.cost;
if (
typeof costDelta === "number" &&
Number.isFinite(costDelta) &&
costDelta > 0
) {
setLastTotalCost((prev) => prev + costDelta);
}
}, []);
const replaceEntries = useCallback((nextEntries: ChatEntry[]) => {
setEntries(
@@ -198,13 +198,8 @@ export function useAutocomplete(opts: {
);
const getFilteredMentionOptions = useCallback(
(query: string): AutocompleteOption[] => {
const q = query.toLowerCase();
let filtered = mentionResults;
if (q) {
filtered = mentionResults.filter((f) => f.toLowerCase().includes(q));
}
return filtered.slice(0, MAX_COMPLETION_RESULTS).map((f) => ({
(_query: string): AutocompleteOption[] => {
return mentionResults.slice(0, MAX_COMPLETION_RESULTS).map((f) => ({
display: f,
value: formatMentionAutocompleteValue(f),
}));
@@ -233,6 +228,7 @@ export function useAutocomplete(opts: {
if (searchTimerRef.current) {
clearTimeout(searchTimerRef.current);
}
setMentionResults([]);
const counter = ++searchCounterRef.current;
searchTimerRef.current = setTimeout(() => {
searchWorkspaceFilesForMention({
@@ -9,6 +9,7 @@ import type {
} from "../../tui/interactive-config";
import type { CliCompactionMode, Config } from "../../utils/types";
import { ExtDetailContent } from "../components/dialogs/config-dialogs";
import { withLoadingDialog } from "../components/dialogs/loading-dialog";
import { ConfigPanelContent } from "../views/config-view";
import type { ConfigAction } from "../views/config-view-helpers";
import type { OpenModelSelectorOptions } from "./use-model-selector";
@@ -43,6 +44,7 @@ export function useConfigPanel(opts: {
plugins: [] as InteractiveConfigItem[],
mcp: [] as InteractiveConfigItem[],
tools: [] as InteractiveConfigItem[],
workflowSlashCommands: [],
}),
[],
);
@@ -50,12 +52,17 @@ export function useConfigPanel(opts: {
const openConfig = useCallback(async () => {
let keepOpen = true;
while (keepOpen) {
const [data, providerInfo] = await Promise.all([
opts
.loadConfigData({ includePluginTools: false })
.catch(() => emptyConfigData),
Llms.getProvider(opts.config.providerId).catch(() => undefined),
]);
const [data, providerInfo] = await withLoadingDialog(
opts.dialog,
"Loading settings...",
async () =>
await Promise.all([
opts
.loadConfigData({ includePluginTools: false })
.catch(() => emptyConfigData),
Llms.getProvider(opts.config.providerId).catch(() => undefined),
]),
);
const providerDisplayName = providerInfo?.name ?? opts.config.providerId;
const action = await opts.dialog.choice<ConfigAction>({
size: "large",
@@ -6,6 +6,7 @@ import type { SlashCommandRegistry } from "../commands/slash-command-registry";
import { resolveSlashCommand } from "../commands/slash-command-registry";
import { ForkConfirmContent } from "../components/dialogs/fork-confirm";
import { HelpDialogContent } from "../components/dialogs/help-dialog";
import { withLoadingDialog } from "../components/dialogs/loading-dialog";
import { useSession } from "../contexts/session-context";
import type { AppView, TuiProps } from "../types";
import { formatCompactionStatus } from "../utils/compaction-status";
@@ -62,28 +63,30 @@ export function useLocalCommandActions(input: {
});
if (sessionId) {
try {
const result = await onResumeSession(sessionId);
const { messages } = result;
const entries = hydrateSessionMessages(messages);
if (entries.length === 0) {
session.appendEntry({
kind: "error",
text: `Session ${sessionId} has no messages to resume.`,
});
} else {
session.clearEntries();
for (const entry of entries) {
session.appendEntry(entry);
await withLoadingDialog(dialog, "Loading session...", async () => {
const result = await onResumeSession(sessionId);
const { messages } = result;
const entries = hydrateSessionMessages(messages);
if (entries.length === 0) {
session.appendEntry({
kind: "error",
text: `Session ${sessionId} has no messages to resume.`,
});
} else {
session.clearEntries();
for (const entry of entries) {
session.appendEntry(entry);
}
if (typeof result.currentContextSize === "number") {
session.setLastTotalTokens(result.currentContextSize);
}
if (typeof result.totalCost === "number") {
session.setLastTotalCost(result.totalCost);
}
session.setHasSubmitted(true);
setAppView("chat");
}
if (typeof result.currentContextSize === "number") {
session.setLastTotalTokens(result.currentContextSize);
}
if (typeof result.totalCost === "number") {
session.setLastTotalCost(result.totalCost);
}
session.setHasSubmitted(true);
setAppView("chat");
}
});
} catch (error) {
session.appendEntry({
kind: "error",
@@ -16,6 +16,7 @@ import {
isProviderConfigured,
} from "../../utils/provider-auth";
import type { Config } from "../../utils/types";
import { withLoadingDialog } from "../components/dialogs/loading-dialog";
import {
CodexCliStatusContent,
type ExistingProviderAction,
@@ -91,8 +92,12 @@ async function runProviderChange(
});
if (!newProviderId) return false;
const displayName = await getProviderDisplayName(newProviderId);
const manager = new ProviderSettingsManager();
const displayName = await withLoadingDialog(
dialog,
"Loading provider...",
async () => await getProviderDisplayName(newProviderId),
);
const existingSettings = manager.getProviderSettings(newProviderId);
let needsAuth = true;
@@ -153,40 +158,48 @@ async function runProviderChange(
}
if (!saved) return false;
}
await refreshProviderModelsFromSource(manager, newProviderId).catch(() => {});
const newSettings = manager.getProviderSettings(newProviderId);
const newApiKey =
getPersistedProviderApiKey(newProviderId, newSettings) ?? "";
await withLoadingDialog(
dialog,
`Loading ${displayName} models...`,
async () => {
await refreshProviderModelsFromSource(manager, newProviderId).catch(
() => {},
);
const newSettings = manager.getProviderSettings(newProviderId);
const newApiKey =
getPersistedProviderApiKey(newProviderId, newSettings) ?? "";
manager.saveProviderSettings(
{
...(newSettings ?? {}),
provider: newProviderId,
manager.saveProviderSettings(
{
...(newSettings ?? {}),
provider: newProviderId,
},
{ setLastUsed: true },
);
config.providerId = newProviderId;
config.apiKey = newApiKey;
const resolved = await resolveProviderConfig(
newProviderId,
{
loadLatestOnInit: true,
loadPrivateOnAuth: true,
failOnError: false,
},
manager.getProviderConfig(newProviderId, { includeKnownModels: false }),
);
config.knownModels = resolved?.knownModels;
const modelIds = Object.keys(resolved?.knownModels ?? {});
if (newSettings?.model) {
config.modelId = newSettings.model;
} else if (modelIds[0]) {
config.modelId = modelIds[0];
}
await onModelChange();
},
{ setLastUsed: true },
);
config.providerId = newProviderId;
config.apiKey = newApiKey;
const resolved = await resolveProviderConfig(
newProviderId,
{
loadLatestOnInit: true,
loadPrivateOnAuth: true,
failOnError: false,
},
manager.getProviderConfig(newProviderId, { includeKnownModels: false }),
);
config.knownModels = resolved?.knownModels;
const modelIds = Object.keys(resolved?.knownModels ?? {});
if (newSettings?.model) {
config.modelId = newSettings.model;
} else if (modelIds[0]) {
config.modelId = modelIds[0];
}
await onModelChange();
return true;
}
@@ -209,11 +222,10 @@ export function useModelSelector(opts: {
refocusTextarea();
};
await refreshCurrentProviderModels(config);
let modelOptions = buildModelOptions(
config.knownModels as Record<string, Llms.ModelInfo>,
);
let providerDisplayName = await getProviderDisplayName(config.providerId);
let providerDisplayName = config.providerId;
const refreshProviderContext = async () => {
modelOptions = buildModelOptions(
@@ -222,6 +234,13 @@ export function useModelSelector(opts: {
providerDisplayName = await getProviderDisplayName(config.providerId);
};
if (!options?.startWithProviderChange) {
await withLoadingDialog(dialog, "Loading models...", async () => {
await refreshCurrentProviderModels(config);
await refreshProviderContext();
});
}
const changeProvider = async (): Promise<boolean> => {
const changed = await runProviderChange(
dialog,
@@ -229,7 +248,11 @@ export function useModelSelector(opts: {
termHeight,
onModelChange,
);
if (changed) await refreshProviderContext();
if (changed) {
await withLoadingDialog(dialog, "Loading models...", async () => {
await refreshProviderContext();
});
}
return changed;
};
@@ -446,7 +469,9 @@ export function useModelSelector(opts: {
pickingModel = false;
}
await onModelChange();
await withLoadingDialog(dialog, "Applying model...", async () => {
await onModelChange();
});
refocusTextarea();
},
[dialog, config, termHeight, onModelChange, refocusTextarea],
@@ -1,11 +1,55 @@
import type { AgentMode } from "@cline/core";
import { useTerminalDimensions } from "@opentui/react";
import type { ChoiceContext } from "@opentui-ui/dialog";
import { useDialog } from "@opentui-ui/dialog/react";
import { useEffect } from "react";
import { AskQuestionContent } from "../components/dialogs/ask-question";
import { ToolApprovalContent } from "../components/dialogs/tool-approval";
import type { TuiProps } from "../types";
import type { ToolApprovalRequest, ToolApprovalResult } from "@cline/shared";
import { useCallback, useEffect, useRef, useState } from "react";
import type { RuntimeToolInteraction, TuiProps } from "../types";
type PendingRuntimeToolInteraction =
| {
id: number;
kind: "tool_approval";
request: ToolApprovalRequest;
resolve: (result: ToolApprovalResult) => void;
}
| {
id: number;
kind: "ask_question";
question: string;
options: string[];
resolve: (answer: string) => void;
};
function toRuntimeToolInteraction(
pending: PendingRuntimeToolInteraction,
): RuntimeToolInteraction {
if (pending.kind === "tool_approval") {
return {
id: pending.id,
kind: pending.kind,
request: pending.request,
};
}
return {
id: pending.id,
kind: pending.kind,
question: pending.question,
options: pending.options,
};
}
function deniedToolResult(request: ToolApprovalRequest): ToolApprovalResult {
return {
approved: false,
reason: `Tool "${request.toolName}" was denied by user`,
};
}
function dismissPendingInteraction(pending: PendingRuntimeToolInteraction) {
if (pending.kind === "tool_approval") {
pending.resolve(deniedToolResult(pending.request));
return;
}
pending.resolve("[User dismissed the question]");
}
export function useRuntimeDialogBridge(input: {
setToolApprover: TuiProps["setToolApprover"];
@@ -14,8 +58,6 @@ export function useRuntimeDialogBridge(input: {
setUiMode: (mode: AgentMode) => void;
refocusTextarea: () => void;
}) {
const dialog = useDialog();
const { height: termHeight } = useTerminalDimensions();
const {
setToolApprover,
setAskQuestion,
@@ -23,38 +65,118 @@ export function useRuntimeDialogBridge(input: {
setUiMode,
refocusTextarea,
} = input;
const [interaction, setInteraction] = useState<RuntimeToolInteraction | null>(
null,
);
const activeRef = useRef<PendingRuntimeToolInteraction | null>(null);
const queueRef = useRef<PendingRuntimeToolInteraction[]>([]);
const nextIdRef = useRef(1);
const activate = useCallback((pending: PendingRuntimeToolInteraction) => {
activeRef.current = pending;
setInteraction(toRuntimeToolInteraction(pending));
}, []);
const enqueue = useCallback(
(pending: PendingRuntimeToolInteraction) => {
if (activeRef.current) {
queueRef.current.push(pending);
return;
}
activate(pending);
},
[activate],
);
const finishActive = useCallback(
(id: number) => {
if (activeRef.current?.id !== id) {
return false;
}
const next = queueRef.current.shift() ?? null;
if (next) {
activate(next);
return true;
}
activeRef.current = null;
setInteraction(null);
return false;
},
[activate],
);
const resolveToolApproval = useCallback(
(id: number, approved: boolean) => {
const pending = activeRef.current;
if (!pending || pending.id !== id || pending.kind !== "tool_approval") {
return;
}
pending.resolve(
approved ? { approved: true } : deniedToolResult(pending.request),
);
const hasNext = finishActive(id);
if (!hasNext) {
refocusTextarea();
}
},
[finishActive, refocusTextarea],
);
const resolveAskQuestion = useCallback(
(id: number, answer: string | null) => {
const pending = activeRef.current;
if (!pending || pending.id !== id || pending.kind !== "ask_question") {
return;
}
pending.resolve(
answer === null ? "[User dismissed the question]" : answer,
);
const hasNext = finishActive(id);
if (!hasNext) {
refocusTextarea();
}
},
[finishActive, refocusTextarea],
);
const dismissAll = useCallback(() => {
if (activeRef.current) {
dismissPendingInteraction(activeRef.current);
activeRef.current = null;
}
for (const pending of queueRef.current) {
dismissPendingInteraction(pending);
}
queueRef.current = [];
setInteraction(null);
}, []);
useEffect(() => {
setToolApprover(async (request) => {
const approved = await dialog.choice<boolean>({
style: { maxHeight: termHeight - 2 },
closeOnEscape: false,
content: (ctx: ChoiceContext<boolean>) => (
<ToolApprovalContent {...ctx} request={request} />
),
});
if (approved) {
return { approved: true };
}
return {
approved: false,
reason: `Tool "${request.toolName}" was denied by user`,
};
});
setAskQuestion(async (question, options) => {
const answer = await dialog.choice<string | null>({
style: { maxHeight: termHeight - 2 },
closeOnEscape: false,
content: (ctx: ChoiceContext<string | null>) => (
<AskQuestionContent {...ctx} question={question} options={options} />
),
});
refocusTextarea();
if (answer === null) {
return "[User dismissed the question]";
}
return answer ?? options[0] ?? "";
});
setToolApprover(
(request) =>
new Promise<ToolApprovalResult>((resolve) => {
enqueue({
id: nextIdRef.current,
kind: "tool_approval",
request,
resolve,
});
nextIdRef.current += 1;
}),
);
setAskQuestion(
(question, options) =>
new Promise<string>((resolve) => {
enqueue({
id: nextIdRef.current,
kind: "ask_question",
question,
options,
resolve,
});
nextIdRef.current += 1;
}),
);
setModeChangeNotifier((mode) => {
setUiMode(mode);
});
@@ -62,14 +184,20 @@ export function useRuntimeDialogBridge(input: {
setToolApprover(null);
setAskQuestion(null);
setModeChangeNotifier(null);
dismissAll();
};
}, [
dialog,
refocusTextarea,
dismissAll,
enqueue,
setAskQuestion,
setModeChangeNotifier,
setToolApprover,
setUiMode,
termHeight,
]);
return {
interaction,
resolveToolApproval,
resolveAskQuestion,
};
}
@@ -18,6 +18,10 @@ import {
type WorkflowConfig,
} from "@cline/core";
import { getToolCatalog } from "../runtime/tools";
import {
type InteractiveSlashCommand,
listInteractiveSlashCommands,
} from "./interactive-welcome";
export type InteractiveConfigTab =
| "general"
@@ -70,6 +74,7 @@ export interface InteractiveConfigData {
plugins: InteractiveConfigItem[];
mcp: InteractiveConfigItem[];
tools: InteractiveConfigItem[];
workflowSlashCommands: InteractiveSlashCommand[];
}
export interface LoadInteractiveConfigDataOptions {
@@ -264,6 +269,9 @@ export async function loadInteractiveConfigData(input: {
const plugins: InteractiveConfigItem[] = [];
const mcp: InteractiveConfigItem[] = [];
const tools: InteractiveConfigItem[] = [];
const workflowSlashCommands = listInteractiveSlashCommands(
input.userInstructionService,
);
if (input.userInstructionService) {
for (const record of input.userInstructionService.listRecords<WorkflowConfig>(
@@ -425,5 +433,6 @@ export async function loadInteractiveConfigData(input: {
plugins: toSorted(plugins.filter((item) => existsSync(item.path))),
mcp: toSorted(mcp.filter((item) => existsSync(item.path))),
tools: toSorted(tools),
workflowSlashCommands,
};
}
@@ -0,0 +1,48 @@
import { describe, expect, it } from "vitest";
import { rankMentionPaths } from "./interactive-welcome";
describe("TUI file mention search ranking", () => {
it("keeps initialism matches for compact and hyphenated input", () => {
const paths = [
"src/components/Button.tsx",
"src/domain/MyAmazingClassDefinition.ts",
"docs/MACD.md",
"packages/core/src/runtime/manager.ts",
];
expect(rankMentionPaths(paths, "MACD", 10)).toEqual([
"docs/MACD.md",
"src/domain/MyAmazingClassDefinition.ts",
]);
expect(rankMentionPaths(paths, "M-A-C-D", 10)).toEqual([
"docs/MACD.md",
"src/domain/MyAmazingClassDefinition.ts",
]);
});
it("normalizes common mention prefixes before matching workspace paths", () => {
const paths = [
"docs/architecture.md",
"src/tui/interactive-welcome.ts",
"src/tui/hooks/use-autocomplete.ts",
];
expect(rankMentionPaths(paths, "./src/tui", 10)).toEqual([
"src/tui/hooks/use-autocomplete.ts",
"src/tui/interactive-welcome.ts",
]);
expect(rankMentionPaths(paths, "/docs", 10)).toEqual([
"docs/architecture.md",
]);
});
it("ranks filename matches ahead of path-only fuzzy matches", () => {
const paths = [
"src/migrations/add-column.ts",
"src/domain/MyAmazingClassDefinition.ts",
"docs/classes.md",
];
expect(rankMentionPaths(paths, "class", 10)[0]).toBe("docs/classes.md");
});
});
+85 -25
View File
@@ -3,6 +3,7 @@ import {
type ProviderSettings,
type UserInstructionConfigService,
} from "@cline/core";
import { byLengthAsc, Fzf, type FzfResultItem } from "fzf";
import type { Config } from "../utils/types";
import { formatClineCredits, loadClineAccountSnapshot } from "./cline-account";
@@ -17,24 +18,95 @@ function normalizeLimit(limit: number | undefined): number {
if (typeof limit !== "number" || Number.isNaN(limit)) {
return 10;
}
return Math.min(50, Math.max(1, Math.trunc(limit)));
return Math.min(200, Math.max(1, Math.trunc(limit)));
}
function rankPath(path: string, query: string): number {
if (query.length === 0) {
return 3;
function getPathLabel(filePath: string): string {
const parts = filePath.split("/");
return parts[parts.length - 1] ?? filePath;
}
function normalizeMentionQuery(query: string): string {
const trimmed = query.trim().replace(/^["']/, "");
if (trimmed.startsWith("./")) {
return trimmed.slice(2);
}
const lowerPath = path.toLowerCase();
if (lowerPath.startsWith(query)) {
return 0;
if (trimmed.startsWith("/")) {
return trimmed.slice(1);
}
if (lowerPath.includes(`/${query}`)) {
return 1;
return trimmed;
}
function compactSearchText(text: string): string {
return text.toLowerCase().replace(/[^a-z0-9]/g, "");
}
interface MentionPathItem {
path: string;
label: string;
searchText: string;
}
function countGaps(positions: Iterable<number>): number {
const sortedPositions = Array.from(positions).sort((a, b) => a - b);
let gaps = 0;
let previous = Number.NEGATIVE_INFINITY;
for (const position of sortedPositions) {
if (previous !== Number.NEGATIVE_INFINITY && position - previous > 1) {
gaps++;
}
previous = position;
}
if (lowerPath.includes(query)) {
return 2;
return gaps;
}
function orderByMatchScore(
left: FzfResultItem<MentionPathItem>,
right: FzfResultItem<MentionPathItem>,
): number {
return countGaps(left.positions) - countGaps(right.positions);
}
export function rankMentionPaths(
paths: Iterable<string>,
query: string,
limit: number,
): string[] {
const items = Array.from(paths, (path): MentionPathItem => {
const label = getPathLabel(path);
return {
path,
label,
searchText: [
label,
label,
path,
compactSearchText(label),
compactSearchText(path),
].join(" "),
};
});
const normalizedQuery = normalizeMentionQuery(query);
if (!normalizedQuery) {
return items
.sort((left, right) => left.path.localeCompare(right.path))
.slice(0, limit)
.map((item) => item.path);
}
return Number.POSITIVE_INFINITY;
const fzf = new Fzf(items, {
selector: (item) => item.searchText,
tiebreakers: [orderByMatchScore, byLengthAsc],
limit,
});
const rawResults = fzf.find(normalizedQuery);
const results =
rawResults.length > 0
? rawResults
: fzf.find(compactSearchText(normalizedQuery));
return results.map((result) => result.item.path);
}
export function listInteractiveSlashCommands(
@@ -90,21 +162,9 @@ export async function searchWorkspaceFilesForMention(input: {
if (!workspaceRoot) {
return [];
}
const query = input.query.trim().toLowerCase();
const limit = normalizeLimit(input.limit);
const index = await getFileIndex(workspaceRoot);
const allPaths = Array.from(index).sort((a, b) => a.localeCompare(b));
return allPaths
.map((path) => ({ path, rank: rankPath(path, query) }))
.filter((item) => Number.isFinite(item.rank))
.sort((left, right) => {
if (left.rank !== right.rank) {
return left.rank - right.rank;
}
return left.path.localeCompare(right.path);
})
.slice(0, limit)
.map((item) => item.path);
return rankMentionPaths(index, input.query, limit);
}
export async function resolveClineWelcomeLine(input: {
+2 -2
View File
@@ -176,11 +176,11 @@ export function getModeInputPlaceholder(
}
function srgbToLinear(c: number): number {
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
}
function linearToSrgb(c: number): number {
const v = c <= 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
const v = c <= 0.0031308 ? c * 12.92 : 1.055 * c ** (1 / 2.4) - 0.055;
return Math.max(0, Math.min(1, v));
}
+46 -14
View File
@@ -87,6 +87,9 @@ function App(props: TuiProps) {
: "home";
});
const [toast, setToast] = useState<ToastState | null>(null);
const [workflowSlashCommands, setWorkflowSlashCommands] = useState(
props.workflowSlashCommands,
);
const toastTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const checkpointRestoreInFlightRef = useRef(false);
@@ -102,13 +105,17 @@ function App(props: TuiProps) {
[appView, props.initialPrompt, session.entries],
);
useEffect(() => {
setWorkflowSlashCommands(props.workflowSlashCommands);
}, [props.workflowSlashCommands]);
const {
registry: slashCommandRegistry,
systemCommands,
skillCommands,
invokableSkillCommands,
} = useSlashCommands({
workflowSlashCommands: props.workflowSlashCommands,
workflowSlashCommands,
loadAdditionalSlashCommands: props.loadAdditionalSlashCommands,
canFork: canForkSession,
});
@@ -187,6 +194,19 @@ function App(props: TuiProps) {
onSessionRestart: props.onSessionRestart,
refocusTextarea: () => refocusTextareaRef.current(),
});
const propsOnToggleConfigItem = props.onToggleConfigItem;
const onToggleConfigItem = useMemo<TuiProps["onToggleConfigItem"]>(() => {
if (!propsOnToggleConfigItem) {
return undefined;
}
return async (item, options) => {
const data = await propsOnToggleConfigItem(item, options);
if (data) {
setWorkflowSlashCommands(data.workflowSlashCommands);
}
return data;
};
}, [propsOnToggleConfigItem]);
const openConfig = useConfigPanel({
dialog,
@@ -198,7 +218,7 @@ function App(props: TuiProps) {
setCompactionMode: session.setCompactionMode,
termHeight,
loadConfigData: props.loadConfigData,
onToggleConfigItem: props.onToggleConfigItem,
onToggleConfigItem,
openModelSelector,
openMcpManager,
refocusTextarea: () => refocusTextareaRef.current(),
@@ -215,10 +235,16 @@ function App(props: TuiProps) {
});
const clearConversation = useCallback(async () => {
const shouldRestartSession = session.hasSubmitted;
session.clearEntries();
session.setHasSubmitted(false);
if (!shouldRestartSession) {
setAppView("home");
refocusTextareaRef.current();
return;
}
try {
await props.onSessionRestart();
await props.onNewSession();
setAppView("home");
} catch (error) {
setAppView("chat");
@@ -708,6 +734,15 @@ function App(props: TuiProps) {
removeLocalCommandInvocationRef.current = (invocation) => {
promptInput.removeLocalCommandInvocation(invocation);
};
const runtimeBridge = useRuntimeDialogBridge({
setToolApprover: props.setToolApprover,
setAskQuestion: props.setAskQuestion,
setModeChangeNotifier: props.setModeChangeNotifier,
setUiMode: session.setUiMode,
refocusTextarea: promptInput.refocusTextarea,
});
const runtimeInteraction = runtimeBridge.interaction;
const isRuntimeInteractionOpen = runtimeInteraction !== null;
const saveQueuedPromptEdit = useCallback(
async (promptId: string, text: string) => {
if (!promptId) return;
@@ -757,9 +792,11 @@ function App(props: TuiProps) {
const initialPromptSubmittedRef = useRef(false);
useEffect(() => {
if (isDialogOpen || appView === "onboarding") return;
if (isDialogOpen || isRuntimeInteractionOpen || appView === "onboarding") {
return;
}
focusPromptTextarea();
}, [isDialogOpen, appView, focusPromptTextarea]);
}, [isDialogOpen, isRuntimeInteractionOpen, appView, focusPromptTextarea]);
useEffect(() => {
if (initialPromptSubmittedRef.current) return;
@@ -774,7 +811,7 @@ function App(props: TuiProps) {
}, [appView, submitInitialPrompt, props.initialPrompt]);
useRootKeyboard({
isDialogOpen,
isDialogOpen: isDialogOpen || isRuntimeInteractionOpen,
appView,
autocomplete,
inputHistory: promptInput.inputHistory,
@@ -804,14 +841,6 @@ function App(props: TuiProps) {
onCommandPaletteShortcut: runCommandPaletteShortcut,
});
useRuntimeDialogBridge({
setToolApprover: props.setToolApprover,
setAskQuestion: props.setAskQuestion,
setModeChangeNotifier: props.setModeChangeNotifier,
setUiMode: session.setUiMode,
refocusTextarea: promptInput.refocusTextarea,
});
const acOptions = autocomplete.getFilteredOptions();
const eventBridgeHandlers = useMemo(
@@ -843,6 +872,9 @@ function App(props: TuiProps) {
void saveQueuedPromptEdit(id, prompt);
},
onToggleMode: toggleMode,
runtimeInteraction,
onResolveToolApproval: runtimeBridge.resolveToolApproval,
onResolveAskQuestion: runtimeBridge.resolveAskQuestion,
autocomplete: {
mode: autocomplete.mode,
options: acOptions,
+14
View File
@@ -103,6 +103,19 @@ export interface PendingPromptMutationResult {
export type AppView = "onboarding" | "home" | "chat";
export type RuntimeToolInteraction =
| {
id: number;
kind: "tool_approval";
request: ToolApprovalRequest;
}
| {
id: number;
kind: "ask_question";
question: string;
options: string[];
};
export interface TuiProps {
config: Config;
initialView?: "chat" | "config";
@@ -149,6 +162,7 @@ export interface TuiProps {
onCompactionModeChange: (mode: CliCompactionMode) => Promise<void>;
onModelChange: () => Promise<void>;
onModeChange: (mode: AgentMode) => Promise<void>;
onNewSession: () => Promise<void>;
onSessionRestart: () => Promise<void>;
onAccountChange: () => Promise<void>;
onResumeSession: (sessionId: string) => Promise<ResumedSessionResult>;
@@ -0,0 +1,88 @@
import { describe, expect, it } from "vitest";
import {
getToolErrorPresentation,
isWarningToolError,
unwrapToolError,
} from "./tool-errors";
describe("tool error presentation", () => {
it("unwraps JSON-encoded tool errors", () => {
const raw = JSON.stringify({
error: "Tool call run_commands was rejected before execution: nope",
});
expect(unwrapToolError(raw)).toBe(
"Tool call run_commands was rejected before execution: nope",
);
});
it("summarizes invalid tool input as a warning", () => {
const raw = JSON.stringify({
error:
'Tool call run_commands was rejected before execution: Invalid input for tool run_commands: Type validation failed: Value: {"commands":[{"command":"cat file"}]}.\nError message: []',
});
expect(getToolErrorPresentation(raw)).toMatchObject({
severity: "warning",
summary: "Invalid run_commands input; tool call skipped.",
});
expect(isWarningToolError(raw)).toBe(true);
});
it("summarizes generic pre-execution rejections as warnings", () => {
expect(
getToolErrorPresentation(
"Tool call editor was rejected before execution: approval request failed",
),
).toMatchObject({
severity: "warning",
summary: "editor call was skipped before execution.",
});
});
it("keeps non-rejection failures as errors", () => {
const presentation = getToolErrorPresentation("command failed with exit 1");
expect(presentation).toEqual({
severity: "error",
summary: "command failed with exit 1",
detail: "command failed with exit 1",
});
});
it("summarizes JSON-wrapped hard errors without dumping stacks", () => {
const raw = JSON.stringify({
error:
"Error: command failed with exit 1\n at runTool (/tmp/tool.ts:10:1)\n at async main (/tmp/main.ts:5:1)",
});
expect(getToolErrorPresentation(raw)).toEqual({
severity: "error",
summary: "command failed with exit 1",
detail:
"Error: command failed with exit 1\n at runTool (/tmp/tool.ts:10:1)\n at async main (/tmp/main.ts:5:1)",
});
});
it("collapses long one-line hard errors", () => {
const detail = `Validation failed: ${"x".repeat(180)}`;
const presentation = getToolErrorPresentation(detail);
expect(presentation.severity).toBe("error");
expect(presentation.detail).toBe(detail);
expect(presentation.summary.length).toBeLessThanOrEqual(140);
expect(presentation.summary.endsWith("...")).toBe(true);
});
it("uses a generic summary when no string error can be extracted", () => {
const presentation = getToolErrorPresentation(
JSON.stringify({ code: "E_TOOL", data: { value: 1 } }),
);
expect(presentation).toEqual({
severity: "error",
summary: "Tool returned a structured error.",
detail: JSON.stringify({ code: "E_TOOL", data: { value: 1 } }),
});
});
});
+118
View File
@@ -0,0 +1,118 @@
export interface ToolErrorPresentation {
severity: "warning" | "error";
summary: string;
detail: string;
}
const MAX_ERROR_SUMMARY_LENGTH = 140;
function extractStringError(value: unknown): string | undefined {
if (typeof value === "string") {
return value.trim() || undefined;
}
if (!value || typeof value !== "object" || Array.isArray(value)) {
return undefined;
}
const record = value as Record<string, unknown>;
return (
extractStringError(record.error) ??
extractStringError(record.message) ??
undefined
);
}
export function unwrapToolError(error: string): string {
let current = error.trim();
for (let i = 0; i < 3; i += 1) {
if (!current.startsWith("{") && !current.startsWith("[")) break;
try {
const parsed = JSON.parse(current) as unknown;
const next = extractStringError(parsed);
if (!next || next === current) break;
current = next.trim();
} catch {
break;
}
}
return current;
}
function summarizeInvalidInput(message: string): string | undefined {
const rejected = message.match(
/^Tool call\s+([A-Za-z0-9_-]+)\s+was rejected before execution:\s+Invalid input for tool\s+([A-Za-z0-9_-]+):\s*([^.\n]+)(?:\.|\n|$)/,
);
if (rejected) {
return `Invalid ${rejected[2]} input; tool call skipped.`;
}
const invalid = message.match(
/^Invalid input for tool\s+([A-Za-z0-9_-]+):\s*([^.\n]+)(?:\.|\n|$)/,
);
if (invalid) {
return `Invalid ${invalid[1]} input; tool call skipped.`;
}
return undefined;
}
function truncateSummary(text: string): string {
const trimmed = text.trim();
if (trimmed.length <= MAX_ERROR_SUMMARY_LENGTH) {
return trimmed;
}
return `${trimmed.slice(0, MAX_ERROR_SUMMARY_LENGTH - 3).trimEnd()}...`;
}
function summarizeErrorDetail(detail: string): string {
const trimmed = detail.trim();
if (!trimmed) {
return "Tool failed.";
}
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
return "Tool returned a structured error.";
}
const firstLine =
trimmed
.replace(/\r\n/g, "\n")
.split("\n")
.map((line) => line.trim())
.find(Boolean) ?? "Tool failed.";
const withoutGenericPrefix = firstLine.replace(/^Error:\s+/i, "");
return truncateSummary(withoutGenericPrefix.replace(/\s+/g, " "));
}
export function getToolErrorPresentation(error: string): ToolErrorPresentation {
const detail = unwrapToolError(error);
const inputSummary = summarizeInvalidInput(detail);
if (inputSummary) {
return {
severity: "warning",
summary: inputSummary,
detail,
};
}
const rejected = detail.match(
/^Tool call\s+([A-Za-z0-9_-]+)\s+was rejected before execution:/,
);
if (rejected) {
return {
severity: "warning",
summary: `${rejected[1]} call was skipped before execution.`,
detail,
};
}
return {
severity: "error",
summary: summarizeErrorDetail(detail),
detail,
};
}
export function isWarningToolError(error: string | undefined): boolean {
return error ? getToolErrorPresentation(error).severity === "warning" : false;
}
+55 -29
View File
@@ -6,6 +6,7 @@ import {
ChatMessageList,
type TranscriptScrollHandle,
} from "../components/chat-message-list";
import { InlineToolResponse } from "../components/inline-tool-response";
import { InputBar, type TextareaHandle } from "../components/input-bar";
import { QueuedPrompts } from "../components/queued-prompts";
import {
@@ -24,7 +25,11 @@ import {
getModeInputForeground,
getModeInputPlaceholder,
} from "../palette";
import type { QueuedPromptItem, TuiProps } from "../types";
import type {
QueuedPromptItem,
RuntimeToolInteraction,
TuiProps,
} from "../types";
export function ChatView(props: {
config: TuiProps["config"];
@@ -51,6 +56,9 @@ export function ChatView(props: {
editingQueuedPrompt?: QueuedPromptItem;
onQueuedPromptEditConfirm: (id: string, prompt: string) => void;
onToggleMode: () => void;
runtimeInteraction?: RuntimeToolInteraction | null;
onResolveToolApproval: (id: number, approved: boolean) => void;
onResolveAskQuestion: (id: number, answer: string | null) => void;
}) {
const {
config,
@@ -73,6 +81,7 @@ export function ChatView(props: {
session.uiMode === "plan" ? "Plan something..." : "Ask anything...";
const modelDisplayName = resolveModelDisplayName(config);
const maxInputTokens = resolveModelMaxInputTokens(config);
const runtimeInteraction = props.runtimeInteraction ?? null;
return (
<box flexDirection="column" width="100%" height="100%">
@@ -84,36 +93,53 @@ export function ChatView(props: {
/>
<box flexDirection="column" flexShrink={0}>
{props.autocomplete && (
<AutocompleteDropdown {...props.autocomplete} accent={accent} />
)}
{runtimeInteraction ? (
<box marginBottom={1}>
<InlineToolResponse
key={runtimeInteraction.id}
interaction={runtimeInteraction}
accent={accent}
inputBackground={inputBackground}
inputForeground={inputForeground}
inputPlaceholder={inputPlaceholder}
onResolveToolApproval={props.onResolveToolApproval}
onResolveAskQuestion={props.onResolveAskQuestion}
/>
</box>
) : (
<>
{props.autocomplete && (
<AutocompleteDropdown {...props.autocomplete} accent={accent} />
)}
{props.queuedPrompts && props.queuedPrompts.length > 0 && (
<QueuedPrompts
items={props.queuedPrompts}
selectedId={props.selectedQueuedPromptId ?? null}
editingId={props.editingQueuedPrompt?.id ?? null}
onEditConfirm={props.onQueuedPromptEditConfirm}
/>
)}
{props.queuedPrompts && props.queuedPrompts.length > 0 && (
<QueuedPrompts
items={props.queuedPrompts}
selectedId={props.selectedQueuedPromptId ?? null}
editingId={props.editingQueuedPrompt?.id ?? null}
onEditConfirm={props.onQueuedPromptEditConfirm}
/>
)}
<box marginBottom={1}>
<InputBar
accent={accent}
inputBackground={inputBackground}
inputForeground={inputForeground}
inputPlaceholder={inputPlaceholder}
placeholder={placeholder}
initialValue={inputValue}
inputKey={inputKey}
onSubmit={onSubmit}
onContentChange={onContentChange}
onImagePaste={onImagePaste}
onLargeTextPaste={onLargeTextPaste}
onFocusRequest={props.onInputFocusRequest}
textareaRef={props.textareaRef}
/>
</box>
<box marginBottom={1}>
<InputBar
accent={accent}
inputBackground={inputBackground}
inputForeground={inputForeground}
inputPlaceholder={inputPlaceholder}
placeholder={placeholder}
initialValue={inputValue}
inputKey={inputKey}
onSubmit={onSubmit}
onContentChange={onContentChange}
onImagePaste={onImagePaste}
onLargeTextPaste={onLargeTextPaste}
onFocusRequest={props.onInputFocusRequest}
textareaRef={props.textareaRef}
/>
</box>
</>
)}
<StatusBar
providerId={config.providerId}
@@ -162,8 +162,35 @@ export function isInlineConfigAction(
return action?.kind === "toggle-item";
}
export function getConfigFooterText(): string {
return "←/→ switch tabs, ↑/↓ navigate, Tab/Enter select, Space toggle, Esc close";
export function canToggleConfigFooterRow(
row:
| { kind: "toggle" }
| { kind: "ext"; enabled?: boolean; item: InteractiveConfigItem }
| { kind: string }
| undefined,
): boolean {
if (!row) {
return false;
}
if (row.kind === "toggle") {
return true;
}
return (
row.kind === "ext" &&
"item" in row &&
typeof row.enabled === "boolean" &&
isToggleableConfigItem(row.item)
);
}
export function getConfigFooterText({
canToggle = false,
}: {
canToggle?: boolean;
} = {}): string {
return canToggle
? "←/→ switch tabs, ↑/↓ navigate, Tab/Enter select, Space toggle, Esc close"
: "←/→ switch tabs, ↑/↓ navigate, Tab/Enter select, Esc close";
}
export function getConfigItemDisplayName(name: string): string {
+40 -3
View File
@@ -1,6 +1,7 @@
import { describe, expect, it } from "vitest";
import type { InteractiveConfigItem } from "../../tui/interactive-config";
import {
canToggleConfigFooterRow,
getAdjacentConfigTab,
getConfigFooterText,
getConfigItemDisplayName,
@@ -36,6 +37,12 @@ describe("config view helpers", () => {
);
});
it("does not treat rule, agent, or hook rows as toggleable", () => {
expect(isToggleableConfigItem(createItem({ kind: "rule" }))).toBe(false);
expect(isToggleableConfigItem(createItem({ kind: "agent" }))).toBe(false);
expect(isToggleableConfigItem(createItem({ kind: "hook" }))).toBe(false);
});
it("keeps plugin tool rows toggleable", () => {
expect(
isToggleableConfigItem(
@@ -75,8 +82,38 @@ describe("config view helpers", () => {
});
});
it("mentions Space toggle in the footer", () => {
expect(getConfigFooterText()).toContain("Space toggle");
it("mentions Space toggle in the footer for toggleable rows", () => {
expect(getConfigFooterText({ canToggle: true })).toContain("Space toggle");
});
it("omits Space toggle in the footer for non-toggleable rows", () => {
expect(getConfigFooterText({ canToggle: false })).not.toContain(
"Space toggle",
);
expect(getConfigFooterText()).not.toContain("Space toggle");
});
it("derives footer toggle affordance from selected row behavior", () => {
const skill = createItem({ kind: "skill" });
const hook = createItem({ kind: "hook" });
expect(canToggleConfigFooterRow({ kind: "provider" })).toBe(false);
expect(canToggleConfigFooterRow({ kind: "toggle" })).toBe(true);
expect(
canToggleConfigFooterRow({
kind: "ext",
enabled: skill.enabled,
item: skill,
}),
).toBe(true);
expect(
canToggleConfigFooterRow({
kind: "ext",
enabled: hook.enabled,
item: hook,
}),
).toBe(false);
expect(canToggleConfigFooterRow({ kind: "mcp-manager" })).toBe(false);
});
it("supports restoring and advancing the active settings tab", () => {
@@ -109,7 +146,7 @@ describe("config view helpers", () => {
expect(
isInlineConfigAction(resolveConfigItemSelectAction(builtinTool)),
).toBe(true);
expect(getConfigFooterText()).not.toContain("details");
expect(getConfigFooterText({ canToggle: true })).not.toContain("details");
});
it("returns item names without decoration", () => {
+77 -1
View File
@@ -17,6 +17,7 @@ import { resolveModelDisplayName } from "../components/status-bar";
import { getModeAccent, palette } from "../palette";
import {
type ConfigAction,
canToggleConfigFooterRow,
getAdjacentConfigTab,
getConfigFooterText,
getConfigItemDisplayName,
@@ -235,6 +236,63 @@ function appendToolRows(
}
}
function withOptimisticToggle(
data: InteractiveConfigData,
item: InteractiveConfigItem,
): InteractiveConfigData {
if (typeof item.enabled !== "boolean") {
return data;
}
const nextEnabled = !item.enabled;
const matchesItem = (candidate: InteractiveConfigItem) =>
candidate.id === item.id &&
candidate.path === item.path &&
candidate.kind === item.kind;
const toolNames = new Set(
(item.toolNames && item.toolNames.length > 0
? item.toolNames
: [item.name]
).filter(Boolean),
);
const updateItems = (items: InteractiveConfigItem[]) =>
items.map((candidate) =>
matchesItem(candidate)
? { ...candidate, enabled: nextEnabled }
: candidate,
);
const updateTools = (items: InteractiveConfigItem[]) =>
items.map((candidate) => {
if (matchesItem(candidate)) {
return { ...candidate, enabled: nextEnabled };
}
if (
item.kind === "tool" &&
toolNames.has(candidate.name) &&
(candidate.source === "builtin" ||
candidate.source === "workspace-plugin" ||
candidate.source === "global-plugin")
) {
return { ...candidate, enabled: nextEnabled };
}
if (item.kind === "plugin" && candidate.path === item.path) {
return { ...candidate, enabled: nextEnabled };
}
return candidate;
});
return {
...data,
workflows: updateItems(data.workflows),
rules: updateItems(data.rules),
skills: updateItems(data.skills),
hooks: updateItems(data.hooks),
agents: updateItems(data.agents),
plugins: updateItems(data.plugins),
mcp: updateItems(data.mcp),
tools: updateTools(data.tools),
};
}
function getPluginLoadErrorLabel(
item: InteractiveConfigItem,
): string | undefined {
@@ -394,6 +452,8 @@ export function ConfigPanelContent(props: ConfigPanelProps) {
const clampedNavPos = Math.min(navPos, Math.max(0, navIndices.length - 1));
const selectedRowIdx = navIndices[clampedNavPos] ?? 0;
const selectedRow = rows[selectedRowIdx];
const canToggleSelectedRow = canToggleConfigFooterRow(selectedRow);
const setNavPosition = (nextNavPos: number) => {
setNavPos(nextNavPos);
@@ -401,8 +461,10 @@ export function ConfigPanelContent(props: ConfigPanelProps) {
const handleInlineToggle = async (item: InteractiveConfigItem) => {
if (!props.onToggleConfigItem || togglingItemId) return;
const previousData = configData;
setTogglingItemId(item.id);
setToggleError(undefined);
setConfigData((current) => withOptimisticToggle(current, item));
try {
const nextData = await props.onToggleConfigItem(item, {
includePluginTools: pluginToolsLoaded,
@@ -410,8 +472,18 @@ export function ConfigPanelContent(props: ConfigPanelProps) {
if (nextData) {
setConfigData(nextData);
setPluginToolsLoaded(nextData.tools.some((tool) => tool.pluginName));
} else if (item.kind === "plugin" && loadConfigData) {
const refreshedData = await loadConfigData({
includePluginTools: true,
});
setConfigData(refreshedData);
setPluginToolsLoaded(
refreshedData.tools.some((tool) => tool.pluginName),
);
setPluginToolsError(undefined);
}
} catch (error) {
setConfigData(previousData);
const message = error instanceof Error ? error.message : String(error);
setToggleError(`Failed to update ${item.name}: ${message}`);
} finally {
@@ -705,7 +777,11 @@ export function ConfigPanelContent(props: ConfigPanelProps) {
<text> </text>
{toggleError && <text fg="red">{toggleError}</text>}
<text fg="gray">
<em>{togglingItemId ? "Applying settings" : getConfigFooterText()}</em>
<em>
{togglingItemId
? "Applying settings"
: getConfigFooterText({ canToggle: canToggleSelectedRow })}
</em>
</text>
</box>
);
+1 -29
View File
@@ -11,10 +11,7 @@ import type { ChoiceContext } from "@opentui-ui/dialog";
import { useDialogKeyboard } from "@opentui-ui/dialog/react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { listSessions } from "../../session/session";
import {
formatSessionStatusLabel,
mergeHistoryStatusRows,
} from "../../utils/history-format";
import { mergeHistoryStatusRows } from "../../utils/history-format";
import { formatUsd } from "../../utils/output";
import { shouldShowCliUsageCost } from "../../utils/usage-cost-display";
import { palette } from "../palette";
@@ -77,25 +74,6 @@ type HistoryListContentProps = HistoryListActions & {
) => void;
};
function getStatusColor(
status: SessionHistoryRecord["status"],
selected: boolean,
): string {
if (selected) {
return palette.textOnSelection;
}
switch (status) {
case "running":
return palette.success;
case "failed":
return "red";
case "cancelled":
return "yellow";
case "completed":
return "gray";
}
}
function HistoryListContent({
initialRows,
onResolve,
@@ -353,7 +331,6 @@ function HistoryListContent({
const showCost = shouldShowCliUsageCost(row.provider);
const title = formatTitle(row, titleMaxLen);
const date = formatRelativeDate(row.startedAt);
const status = formatSessionStatusLabel(row.status);
return (
<box
@@ -377,11 +354,6 @@ function HistoryListContent({
>
{title}
</text>
<text fg={getStatusColor(row.status, isSel)} flexShrink={0}>
{" ["}
{status}
{"]"}
</text>
{showCost && cost != null && cost > 0 && (
<text
fg={isSel ? palette.textOnSelection : "gray"}
@@ -28,13 +28,13 @@ import {
useSearchableList,
} from "../../components/searchable-list";
import { palette } from "../../palette";
import { getProviderSection } from "../../utils/provider-sections";
import {
getDefaultAwsRegion,
type ProviderConfigValues,
resolveProviderConfigAwsRegion,
updateProviderConfigValue,
type ProviderConfigValues,
} from "../../utils/provider-config-values";
import { getProviderSection } from "../../utils/provider-sections";
import {
isOnboardingOAuthProviderId,
type OnboardingOAuthProviderId,
@@ -284,6 +284,7 @@ export function OnboardingProviderConfigScreen(props: {
width={props.contentWidth}
>
<text fg="gray">{label}</text>
{requirement.note && <text fg="gray">{requirement.note}</text>}
<box
border
borderStyle="rounded"
@@ -2,6 +2,13 @@ import { describe, expect, it } from "vitest";
import { PLATFORMS } from "./platforms";
describe("connect wizard platform security fields", () => {
it("does not ask Telegram users to re-enter the bot username", () => {
const telegram = PLATFORMS.find((platform) => platform.id === "telegram");
expect(telegram?.fields.map((field) => field.label)).toEqual(["Bot token"]);
expect(telegram?.fields.map((field) => field.flag)).toEqual(["-k"]);
});
it("rejects unsafe Telegram and Slack access restriction identifiers", () => {
const telegram = PLATFORMS.find((platform) => platform.id === "telegram");
const slack = PLATFORMS.find((platform) => platform.id === "slack");
+2 -11
View File
@@ -55,23 +55,14 @@ export const PLATFORMS: PlatformDef[] = [
type: "polling",
hint: "Easiest to set up. No public URL needed.",
fields: [
{
flag: "-m",
label: "Bot username",
placeholder: "my_cline_bot",
required: true,
help: [
"Open Telegram and start a chat with @BotFather",
"Send /newbot and follow the prompts",
"The username must end in 'bot'",
],
},
{
flag: "-k",
label: "Bot token",
placeholder: "7123456789:AAH...",
required: true,
help: [
"Open Telegram and start a chat with @BotFather",
"Send /newbot and follow the prompts",
"BotFather gives you this after creating the bot",
"It looks like 7123456789:AAHxxx...",
],
+1
View File
@@ -33,6 +33,7 @@ Requires Node.js 22+.
|---------|-------------|----------|
| [quickstart](./quickstart) | Send one prompt, stream the response. ~15 lines of code. | `Agent`, `subscribe`, `run()` |
| [cli-agent](./cli-agent) | Interactive terminal chat with a shell tool. | `createTool`, multi-turn `run()`/`continue()`, streaming |
| [cline-core-cli-agent](./cline-core-cli-agent) | Interactive terminal chat powered by ClineCore. | `ClineCore.create()`, `cline.start()`, `cline.send()`, built-in tools, streaming |
### Intermediate
@@ -0,0 +1,57 @@
# Cline Core CLI Agent
An interactive terminal chat agent powered by the `ClineCore` runtime. This example is similar in spirit to [`cli-agent`](../cli-agent), but uses stateful ClineCore sessions and built-in runtime tools instead of the stateless `Agent` class, to leverage Cline's internal agent harness.
## Getting started
Install dependencies:
```bash
bun install
bun run build:sdk
```
Set an API key:
```bash
export CLINE_API_KEY="sk_..."
```
Run:
```bash
bun dev
```
Type any message at the `you:` prompt to see a streaming response. Type `exit` to quit.
## Optional model configuration
The example defaults to Cline's gateway provider and Claude Sonnet:
```bash
export CLINE_PROVIDER_ID="cline"
export CLINE_MODEL_ID="anthropic/claude-sonnet-4.6"
```
## What it does
- Creates a local `ClineCore` runtime with `ClineCore.create()`
- Starts one interactive session with `cline.start()`
- Sends each user turn with `cline.send({ sessionId, prompt })`
- Streams `agent_event` text to stdout as the assistant responds
- Logs tool calls and tool results inline
- Uses ClineCore's built-in tools instead of defining custom tools
- Calls `cline.stop()` and `cline.dispose()` during shutdown
## Concepts demonstrated
- Stateful sessions with `ClineCore`
- Multi-turn conversation using a single `sessionId`
- `CoreSessionEvent` subscription via `cline.subscribe()`
- Built-in runtime tools (`read_files`, `search_codebase`, `run_commands`, etc.)
- Basic tool policies: file reads/search are auto-approved, other tools request approval
## Notes
Use this example when you want the full ClineCore runtime with sessions, persistence, and built-in tools. For the smallest possible SDK example, see [quickstart](../quickstart). For the lightweight stateless runtime, see [cli-agent](../cli-agent).
@@ -0,0 +1,21 @@
{
"name": "@cline/example-cline-core-cli-agent",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "bun run src/index.ts",
"build:sdk": "bun run --cwd ../../.. build:sdk",
"build": "tsc",
"start": "node dist/index.js"
},
"dependencies": {
"@cline/sdk": "workspace:*"
},
"devDependencies": {
"typescript": "^5.9.3"
},
"engines": {
"node": ">=22"
}
}
@@ -0,0 +1,185 @@
import * as readline from "node:readline";
import {
type AgentEvent,
ClineCore,
type ToolApprovalRequest,
} from "@cline/sdk";
// ClineCore does not choose a model automatically; each session config must provide one.
// These example defaults use the Cline gateway with Claude Sonnet, and can be overridden with env vars.
const providerId = process.env.CLINE_PROVIDER_ID ?? "cline";
const modelId = process.env.CLINE_MODEL_ID ?? "anthropic/claude-sonnet-4.6";
const apiKey = process.env.CLINE_API_KEY;
const cwd = process.cwd();
const systemPrompt = `You are a helpful assistant in an interactive terminal chat.
Be concise. You can use built-in tools to inspect files, search the workspace, and run shell commands when helpful.`;
let cline: ClineCore | undefined;
let unsubscribe: (() => void) | undefined;
let activeSessionId: string | undefined;
let hasPrintedAssistantPrefix = false;
function printAssistantPrefix(): void {
if (!hasPrintedAssistantPrefix) {
process.stdout.write("\nagent: ");
hasPrintedAssistantPrefix = true;
}
}
function formatToolValue(value: unknown): string {
const output =
typeof value === "string" ? value : (JSON.stringify(value, null, 2) ?? "");
return output.length > 200 ? `${output.slice(0, 200)}...` : output;
}
function handleAgentEvent(event: AgentEvent): void {
switch (event.type) {
case "content_start":
if (event.contentType === "text" && event.text) {
printAssistantPrefix();
process.stdout.write(event.text);
}
if (event.contentType === "tool" && event.toolName) {
console.log(
`\n[tool] ${event.toolName}(${JSON.stringify(event.input ?? {})})`,
);
}
break;
case "content_update":
if (event.contentType === "tool" && event.toolName) {
console.log(
`[update] ${event.toolName}: ${formatToolValue(event.update)}`,
);
}
break;
case "content_end":
if (event.contentType === "tool" && event.toolName) {
if (event.error) {
console.log(`[error] ${event.toolName}: ${event.error}`);
} else {
console.log(`[result] ${formatToolValue(event.output)}`);
}
}
break;
case "notice":
console.log(`\n[notice] ${event.message}`);
break;
case "error":
console.error(`\n[error] ${event.error.message}`);
break;
}
}
async function ensureCline(): Promise<ClineCore> {
if (cline) {
return cline;
}
cline = await ClineCore.create({
clientName: "cline-core-cli-agent",
backendMode: "local",
capabilities: {
requestToolApproval,
},
});
unsubscribe = cline.subscribe((event) => {
if (event.type === "agent_event") {
handleAgentEvent(event.payload.event);
}
});
return cline;
}
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
function ask(question: string): Promise<string> {
return new Promise((resolve) => {
rl.question(question, resolve);
});
}
async function requestToolApproval(request: ToolApprovalRequest) {
console.log(`\n[approval] ${request.toolName} wants to run:`);
console.log(formatToolValue(request.input));
const answer = await ask("Approve? [y/N] ");
const approved = answer.trim().toLowerCase() === "y";
return {
approved,
...(approved ? {} : { reason: "User denied tool execution" }),
};
}
function prompt(): Promise<string> {
return ask("\nyou: ");
}
async function startSession(): Promise<string> {
const runtime = await ensureCline();
const result = await runtime.start({
source: "cli",
interactive: true,
config: {
providerId,
modelId,
apiKey,
cwd,
workspaceRoot: cwd,
mode: "act",
systemPrompt,
maxIterations: 10,
enableTools: true,
enableSpawnAgent: false,
enableAgentTeams: false,
disableMcpSettingsTools: true,
},
toolPolicies: {
"*": { autoApprove: false },
read_files: { autoApprove: true },
search_codebase: { autoApprove: true },
},
});
return result.sessionId;
}
async function runTurn(input: string): Promise<void> {
activeSessionId ??= await startSession();
hasPrintedAssistantPrefix = false;
const runtime = await ensureCline();
await runtime.send({
sessionId: activeSessionId,
prompt: input,
});
console.log();
}
console.log("ClineCore CLI Agent (type 'exit' to quit)\n");
console.log(`Provider: ${providerId}`);
console.log(`Model: ${modelId}`);
console.log(`CWD: ${cwd}`);
try {
while (true) {
const input = await prompt();
const trimmed = input.trim();
if (trimmed.toLowerCase() === "exit") {
break;
}
if (!trimmed) {
continue;
}
await runTurn(trimmed);
}
} finally {
rl.close();
unsubscribe?.();
if (activeSessionId && cline) {
await cline.stop(activeSessionId).catch(() => undefined);
}
await cline?.dispose();
console.log("Goodbye!");
}
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.apps.json",
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "dist",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true
},
"include": ["src"]
}
+21 -7
View File
@@ -1,4 +1,8 @@
import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
import {
createServer,
type IncomingMessage,
type ServerResponse,
} from "node:http";
import { Agent, createTool } from "@cline/sdk";
import { z } from "zod";
@@ -1438,9 +1442,12 @@ async function loadPullRequest(prUrl: string): Promise<PullRequestBundle> {
githubPaged<GitHubPullFile>(
`https://api.github.com/repos/${ref.owner}/${ref.repo}/pulls/${ref.number}/files`,
),
githubText(`https://api.github.com/repos/${ref.owner}/${ref.repo}/pulls/${ref.number}`, {
headers: { Accept: "application/vnd.github.v3.diff" },
}),
githubText(
`https://api.github.com/repos/${ref.owner}/${ref.repo}/pulls/${ref.number}`,
{
headers: { Accept: "application/vnd.github.v3.diff" },
},
),
loadChecks(ref, pr.head.sha),
]);
@@ -1464,7 +1471,8 @@ async function loadChecks(ref: PullRequestRef, sha: string) {
(run) => run.status !== "completed",
);
if (failedChecks.length > 0 || status.state === "failure") return "failing";
if (pendingChecks.length > 0 || status.state === "pending") return "pending";
if (pendingChecks.length > 0 || status.state === "pending")
return "pending";
if (checks.total_count > 0 || status.total_count > 0) return "passing";
return "unknown";
} catch {
@@ -1566,7 +1574,8 @@ async function githubText(url: string, init: RequestInit = {}) {
async function githubFetch(url: string, init: RequestInit = {}) {
const headers = new Headers(init.headers);
if (!headers.has("Accept")) headers.set("Accept", "application/vnd.github+json");
if (!headers.has("Accept"))
headers.set("Accept", "application/vnd.github+json");
headers.set("User-Agent", "cline-sdk-code-review-bot-example");
headers.set("X-GitHub-Api-Version", "2022-11-28");
if (GITHUB_TOKEN) headers.set("Authorization", `Bearer ${GITHUB_TOKEN}`);
@@ -1614,7 +1623,12 @@ function formatReviewComment(
const lines = ["## AI Review Bot", ""];
if (summary) {
lines.push(summary.summary, "");
lines.push(summary.approve ? "**Status:** Looks safe to merge." : "**Status:** Changes requested.", "");
lines.push(
summary.approve
? "**Status:** Looks safe to merge."
: "**Status:** Changes requested.",
"",
);
}
if (findings.length === 0) {
+15 -5
View File
@@ -152,7 +152,9 @@ function asString(value: unknown): string | undefined {
}
function asNumber(value: unknown): number | undefined {
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
return typeof value === "number" && Number.isFinite(value)
? value
: undefined;
}
function basename(value: string | undefined): string {
@@ -271,7 +273,9 @@ function summarizeClient(client: TrackedClient): {
};
}
function sessionTitle(session: SessionRecord | Record<string, unknown>): string {
function sessionTitle(
session: SessionRecord | Record<string, unknown>,
): string {
const raw = session as Record<string, unknown>;
const metadata = metadataFor(session);
const title = asString(metadata.title);
@@ -827,7 +831,9 @@ async function main(): Promise<void> {
const previousStatus = existing.status;
existing.status = status;
existing.updatedAt =
asNumber(session.updatedAt) ?? asNumber(session.endedAt) ?? Date.now();
asNumber(session.updatedAt) ??
asNumber(session.endedAt) ??
Date.now();
existing.title = sessionTitle(session);
existing.workspaceRoot =
typeof session.workspaceRoot === "string"
@@ -852,7 +858,11 @@ async function main(): Promise<void> {
events,
`Session ${status}`,
`${existing.title ?? shortSessionId(sessionId)} changed from ${previousStatus}`,
status === "running" ? "success" : status === "idle" ? "info" : "warn",
status === "running"
? "success"
: status === "idle"
? "info"
: "warn",
);
}
} else {
@@ -873,7 +883,7 @@ async function main(): Promise<void> {
? session.sessionId
: typeof payload.sessionId === "string"
? payload.sessionId
: undefined;
: undefined;
if (!sessionId) return;
const participantCount = Array.isArray(session?.participants)
? session.participants.length
+1 -1
View File
@@ -1,5 +1,5 @@
import { Agent } from "@cline/sdk";
import { createServer } from "node:http";
import { Agent } from "@cline/sdk";
const PORT = Number(process.env.PORT || 3456);
+19 -4
View File
@@ -18,6 +18,7 @@ import {
readHubDiscovery,
rememberRecoverableLocalHubUrl,
resolveSharedHubOwnerContext,
type SendSessionConnectionUpdate,
type ToolPolicy,
} from "@cline/core";
import {
@@ -1022,13 +1023,14 @@ class CoreChatWebviewController implements vscode.Disposable {
this.sending = true;
try {
await this.ensureSession(config);
const startConfig = await this.ensureSession(config);
const host = await this.getSessionHost();
const activeSessionId = this.sessionId as string;
await host.send({
sessionId: activeSessionId,
prompt: trimmedPrompt,
userImages: attachments?.userImages,
connection: buildConnectionUpdate(startConfig),
});
await this.refreshSessions();
} catch (error) {
@@ -1147,6 +1149,12 @@ class CoreChatWebviewController implements vscode.Disposable {
if (this.sessionId && this.startConfig) {
if (areStartConfigsEqual(this.startConfig, startConfig)) {
this.startConfig = {
...this.startConfig,
providerId: startConfig.providerId,
modelId: startConfig.modelId,
thinking: startConfig.thinking,
};
return this.startConfig;
}
await this.stopExistingSession();
@@ -1537,13 +1545,10 @@ class CoreChatWebviewController implements vscode.Disposable {
*/
function areStartConfigsEqual(a: StartConfig, b: StartConfig): boolean {
return (
a.providerId === b.providerId &&
a.modelId === b.modelId &&
a.cwd === b.cwd &&
a.workspaceRoot === b.workspaceRoot &&
a.systemPrompt === b.systemPrompt &&
a.maxIterations === b.maxIterations &&
a.thinking === b.thinking &&
a.enableTools === b.enableTools &&
a.enableSpawnAgent === b.enableSpawnAgent &&
a.enableAgentTeams === b.enableAgentTeams &&
@@ -1559,6 +1564,16 @@ function areStartConfigsEqual(a: StartConfig, b: StartConfig): boolean {
);
}
function buildConnectionUpdate(
config: StartConfig,
): SendSessionConnectionUpdate {
return {
providerId: config.providerId,
modelId: config.modelId,
thinking: config.thinking === true,
};
}
function createToolPolicies(config: StartConfig): Record<string, ToolPolicy> {
return {
"*": { autoApprove: config.autoApproveTools !== false },
+202 -243
View File
@@ -19,7 +19,7 @@
},
"apps/cli": {
"name": "@cline/cli",
"version": "3.0.3",
"version": "3.0.11",
"bin": {
"cline": "src/index.ts",
},
@@ -38,6 +38,7 @@
"@opentui/react": "0.1.102",
"chat": "^4.23.0",
"commander": "^14.0.3",
"fzf": "^0.5.2",
"marked": "^15.0.12",
"open": "^10.2.0",
"opentui-spinner": "^0.0.6",
@@ -66,6 +67,16 @@
"typescript": "^5.9.3",
},
},
"apps/examples/cline-core-cli-agent": {
"name": "@cline/example-cline-core-cli-agent",
"version": "0.0.0",
"dependencies": {
"@cline/sdk": "workspace:*",
},
"devDependencies": {
"typescript": "^5.9.3",
},
},
"apps/examples/code-review-bot": {
"name": "@cline/example-code-review-bot",
"version": "0.0.0",
@@ -287,7 +298,7 @@
},
"packages/agents": {
"name": "@cline/agents",
"version": "0.0.41",
"version": "0.0.42",
"dependencies": {
"@cline/llms": "workspace:*",
"@cline/shared": "workspace:*",
@@ -296,7 +307,7 @@
},
"packages/core": {
"name": "@cline/core",
"version": "0.0.41",
"version": "0.0.42",
"dependencies": {
"@cline/agents": "workspace:*",
"@cline/llms": "workspace:*",
@@ -327,7 +338,7 @@
},
"packages/llms": {
"name": "@cline/llms",
"version": "0.0.41",
"version": "0.0.42",
"dependencies": {
"@ai-sdk/amazon-bedrock": "^4.0.89",
"@ai-sdk/anthropic": "^3.0.68",
@@ -360,14 +371,14 @@
},
"packages/sdk": {
"name": "@cline/sdk",
"version": "0.0.41",
"version": "0.0.42",
"dependencies": {
"@cline/core": "workspace:*",
},
},
"packages/shared": {
"name": "@cline/shared",
"version": "0.0.41",
"version": "0.0.42",
"dependencies": {
"aws4fetch": "^1.0.20",
"jsonrepair": "^3.13.2",
@@ -379,19 +390,19 @@
"packages": {
"@agentclientprotocol/sdk": ["@agentclientprotocol/sdk@0.16.1", "", { "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" } }, "sha512-1ad+Sc/0sCtZGHthxxvgEUo5Wsbw16I+aF+YwdiLnPwkZG8KAGUEAPK6LM6Pf69lCyJPt1Aomk1d+8oE3C4ZEw=="],
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.105", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.77", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-mNnJeRTIYRL2I2MS9ElRJTFMSeHqbx5EMCVsIlEKKTI4+2O+Zu0K7Rtp16HRXtxMepJF1Y756rAmUm/JvuXOGg=="],
"@ai-sdk/amazon-bedrock": ["@ai-sdk/amazon-bedrock@4.0.108", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.79", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-cVAzseR9OoSSL7966TMj2uUbDOL2e1LaH2JXrWvyMXQvF5Me2rPfzdA06k/vhYjP0DQq1uvsZPRojmg4ghiI9g=="],
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.77", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ML8C2M1YvPA1ulEx4TiyF0k1xvC2ikEiPBIC1PPQ0a5xELUGrO2lAaEzsTEoJ+eCeDd8PSBuFJjs+r+9yIwQXA=="],
"@ai-sdk/anthropic": ["@ai-sdk/anthropic@3.0.79", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-saEX+h5JDOkT9P/+REKDyikbnJiToFuLipgNcsmu4Zr3GW5kW1m9HhvrPK+vj63itIOsoZU6tmVIjkrePOlIUA=="],
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.114", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MqkZ5sd+qiq6RgIxELkoFQXg2/JwK+WCMaot7U+rtrZpWJl3fSyYvc28SC03b256o4F7OXjQtdjTqs81B2w+dA=="],
"@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.119", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-VAhfRWC+JexZakkVfmjaJKaTj00x7/UHdE8kMWL3NhuQAlf8oXtg9r4dfvFZrByXxchGRBvYE3biEUyibkg0xg=="],
"@ai-sdk/google": ["@ai-sdk/google@3.0.73", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-o2MuIeyvZrFIeIbnbA8Thrr63irdyUBh0uWBZ2lY6yFeXuE/tcwyXF74bDKS4KvTu84uFpQfpbS/LXHGKKXz+g=="],
"@ai-sdk/google": ["@ai-sdk/google@3.0.79", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-QWVAvYeA7JzEX2wkSyXOWv/I9PD9kvTzdykkSTLi+Eu8RyJ6gA0tdPIGa8esEtOcHE//G5vy6FTB70qQw8l/uw=="],
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.128", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.77", "@ai-sdk/google": "3.0.73", "@ai-sdk/openai-compatible": "2.0.47", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-jK8fixb4km2yfgvb9DUFQRpV/jiDB0v9gyxHoHfPydaQvz+CpAz8DTt1quyaM+Wg9G2R8Zo68CYmHbIkUqW2AA=="],
"@ai-sdk/google-vertex": ["@ai-sdk/google-vertex@4.0.136", "", { "dependencies": { "@ai-sdk/anthropic": "3.0.79", "@ai-sdk/google": "3.0.79", "@ai-sdk/openai-compatible": "2.0.47", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "google-auth-library": "^10.5.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-h6y520LNDm61QSsa9phEfX1uSVHmLLGvfSu2JkFYqui+cu0SEui60WDe9R0vJ8bl9q54+qVzxctFN+7LuXX5lA=="],
"@ai-sdk/mistral": ["@ai-sdk/mistral@3.0.36", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-FLIb2QdLraOgQP3puUybuFYWbtsB02YWQBTOJOk8heiEsdFW3YE0dfuzwtsvoF4FXlBnbYYMWu5jgOesthcmWg=="],
"@ai-sdk/mistral": ["@ai-sdk/mistral@3.0.37", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-KkdaMjs4C2y+vrZWJE990E3ZxBFiOTHQ94ZlquuIttpphcqJTMxNoIpnKT/4UzMVWXL0BUEE2vs+1UEVXkN8Kg=="],
"@ai-sdk/openai": ["@ai-sdk/openai@3.0.63", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-4yY/m8a57MNNVoJCsXuNblKf6BO4yuAuLKRX4tzSNffBEBSp1FlcWdPE0Z4FkqUeS0AJhYSSqp0GIiA/cIcDNA=="],
"@ai-sdk/openai": ["@ai-sdk/openai@3.0.65", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZlVoWH+zrdiYDiUt6n/xvfCsk33mzsB81TUQkBRVx79rxU1FKZqVH9J/QCtEpSLqx0cUzjvtIw9l9p7EbUv+dw=="],
"@ai-sdk/openai-compatible": ["@ai-sdk/openai-compatible@2.0.47", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-Enm5UlL0zUCrW3792opk5h7hRWxZOZzDe6eQYVFqX9LUOGGCe1h8MZWAGim765nwzgnjlpeYOsuzZmLtRsTPlg=="],
@@ -399,31 +410,31 @@
"@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="],
"@ai-sdk/react": ["@ai-sdk/react@3.0.182", "", { "dependencies": { "@ai-sdk/provider-utils": "4.0.27", "ai": "6.0.180", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1" } }, "sha512-cnfF5N6XRsQ29VsSSoFqFpYQJx1y4sSCL3lGMIwgE0034aqn8i3+joRe52O9xV+EaJ7fziI7xn6ql7qjrf+Blw=="],
"@ai-sdk/react": ["@ai-sdk/react@3.0.192", "", { "dependencies": { "@ai-sdk/provider-utils": "4.0.27", "ai": "6.0.190", "swr": "^2.2.5", "throttleit": "2.1.0" }, "peerDependencies": { "react": "^18 || ~19.0.1 || ~19.1.2 || ^19.2.1" } }, "sha512-QB7ViYcM1o2zN6Zo1nVD1FqAkiivCPOi1vmT/OmWAxctmXUGTdWOL7MBs9q3zuzPbZpkty4xDERwemWYoZx6Kw=="],
"@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="],
"@antfu/install-pkg": ["@antfu/install-pkg@1.1.0", "", { "dependencies": { "package-manager-detector": "^1.3.0", "tinyexec": "^1.0.1" } }, "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ=="],
"@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.2.140", "", { "dependencies": { "@anthropic-ai/sdk": "^0.81.0", "@modelcontextprotocol/sdk": "^1.29.0" }, "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.2.140", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.2.140", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.2.140", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.2.140", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.2.140", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.2.140", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.2.140", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.2.140" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-Zq2L7YCoTdbxTUi3/soN1axrTqbG7GoKuc6Im8EpkBRdwaY0D1W9+Ux3vAbV/cX8Qk31Vck7DQLZz1lGEArdoQ=="],
"@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-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.2.140", "", { "os": "darwin", "cpu": "arm64" }, "sha512-zEbDsDKeoDO4DzbyX6wBVlcPhLy/gYiCrKzKnxmkOhyNtJBeshgiOTdr+M7WX1xcuI/M/UhEY+B9U6oo884lAQ=="],
"@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-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.2.140", "", { "os": "darwin", "cpu": "x64" }, "sha512-BFJGeZEksvERy7mMJ0mkNAWoMrZOgl6XN/mKPaunGnaC/i+1ykx7xih7e58bRhsrzKzo2mnUrwtjiFyF3MFNRQ=="],
"@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-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.2.140", "", { "os": "linux", "cpu": "arm64" }, "sha512-FauGGg3zikxrjAUnu+Pso6zD9Qv4Z2+QBiTiZqc12U+x4uoikNsplymUnsJ7MYD9VaTGmLJuZ9pCch0IiKrseQ=="],
"@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-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.2.140", "", { "os": "linux", "cpu": "arm64" }, "sha512-nG7xLL0nKb4ymFVnX0QhSGLoyhh9fuuDpBR+TYz5O4ZQc2RVUMSMqGusqcCNEIGxAKQSVKWCf0WgpCG/edAO9Q=="],
"@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-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.2.140", "", { "os": "linux", "cpu": "x64" }, "sha512-7f627Tq2mIiwFoBYfCKTdEeZSP90r8UOWu/I5DezudTtwtoVl2zRaRCnJ8c4rW+Tzw+xWSfP/pHvR9bTQGXaOw=="],
"@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-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.2.140", "", { "os": "linux", "cpu": "x64" }, "sha512-EZ7VzOGmvft/1ymh2rwts5v3yPnsGGlGrTJlY2Dqnr1ABF43JIhEm1NFYrLnXQWSN74s5Pj8tgkPbYS9x4BhFA=="],
"@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-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.2.140", "", { "os": "win32", "cpu": "arm64" }, "sha512-9EOozRF+LTt3UedeJtjJXC8pj9VTAFtPBuB+/YUmcpmDAEH9qcWWknWhf7NDKTapKtBWkNP/387x+18L15MLqg=="],
"@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-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.2.140", "", { "os": "win32", "cpu": "x64" }, "sha512-puQyWoYiqosjDEYULWAS/lBJse1vzib0NmQj/bYTirWCbtiUcu6ixKMd4NmLbE+Si/DKTB8XNz6hVZ/KckqeoQ=="],
"@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/sdk": ["@anthropic-ai/sdk@0.81.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-D4K5PvEV6wPiRtVlVsJHIUhHAmOZ6IT/I9rKlTf84gR7GyyAurPJK7z9BOf/AZqC5d1DhYQGJNKRmV+q8dGhgw=="],
"@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=="],
"@aws-crypto/crc32": ["@aws-crypto/crc32@5.2.0", "", { "dependencies": { "@aws-crypto/util": "^5.2.0", "@aws-sdk/types": "^3.222.0", "tslib": "^2.6.2" } }, "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg=="],
@@ -435,61 +446,41 @@
"@aws-crypto/util": ["@aws-crypto/util@5.2.0", "", { "dependencies": { "@aws-sdk/types": "^3.222.0", "@smithy/util-utf8": "^2.0.0", "tslib": "^2.6.2" } }, "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ=="],
"@aws-sdk/client-cognito-identity": ["@aws-sdk/client-cognito-identity@3.1045.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.8", "@aws-sdk/credential-provider-node": "^3.972.39", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.38", "@aws-sdk/region-config-resolver": "^3.972.13", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.8", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.24", "@smithy/config-resolver": "^4.4.17", "@smithy/core": "^3.23.17", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.32", "@smithy/middleware-retry": "^4.5.7", "@smithy/middleware-serde": "^4.2.20", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.6.1", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.49", "@smithy/util-defaults-mode-node": "^4.2.54", "@smithy/util-endpoints": "^3.4.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.6", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-3OEn8zvtfJoN0jFfjVJ9jF2GVRDL3IjDfk6CAgVTAqjfCVjajiUD0iFAGQ4cOzdcv1LGsZ0b/snJDWalY3OePQ=="],
"@aws-sdk/client-cognito-identity": ["@aws-sdk/client-cognito-identity@3.1053.0", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.13", "@aws-sdk/credential-provider-node": "^3.972.44", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/fetch-http-handler": "^5.4.3", "@smithy/node-http-handler": "^4.7.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-fMwSPTOWcYrKsB1NG1z9uRSLE/GDJR/375tjiAyO6z2UTlpLSuWkfoYx98oMwHaJpqb1fEhtZZQ7o8czblShJQ=="],
"@aws-sdk/core": ["@aws-sdk/core@3.974.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws-sdk/xml-builder": "^3.972.22", "@smithy/core": "^3.23.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-base64": "^4.3.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.6", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-njR2qoG6ZuB0kvAS2FyICsFZJ6gmCcf2X/7JcD14sUvGDm26wiZ5BrA6LOiUxKFEF+IVe7kdroxyE00YlkiYsw=="],
"@aws-sdk/core": ["@aws-sdk/core@3.974.13", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@aws-sdk/xml-builder": "^3.972.25", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/core": "^3.24.3", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.2", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-+Y5/4tHki0uYgyx8eun146DegRVQBpdKGK5RbV0FTKJPpaKTchvqVxrrRFK6Wk0JksO4iAZKw3eqxGEIwtO98w=="],
"@aws-sdk/credential-provider-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.972.31", "", { "dependencies": { "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-W5JtzDp3ejzhOOknXlnt+vJsNN2GZdAcBK+hR7HQ1DCacXqS0UpmnIyihIU7CK0IB+XYWeBaN3bBv4pXavp7Vg=="],
"@aws-sdk/credential-provider-cognito-identity": ["@aws-sdk/credential-provider-cognito-identity@3.972.36", "", { "dependencies": { "@aws-sdk/nested-clients": "^3.997.11", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-DkibmGSpgUKUwqvbooEnwoU/18pbrneuOcysCwHolC85Q6UXGesZ73Sk00oK/SpWOe+lfjDxq2nMDypJvi2OmQ=="],
"@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.34", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-XT0jtf8Fw9JE6ppsQeoNnZRiG+jqRixMT1v1ZR17G60UvVdsQmTG8nbEyHuEPfMxDXEhfdARaM/XiEhca4lGHQ=="],
"@aws-sdk/credential-provider-env": ["@aws-sdk/credential-provider-env@3.972.39", "", { "dependencies": { "@aws-sdk/core": "^3.974.13", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-29wX9zpAvEt1vcj0psha+y6ygBHy2V/S72mp6e7q0KARLWXq+pwE/lR6qGkwknQvruh52lXvlqZIga8Hdxkucw=="],
"@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.36", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/node-http-handler": "^4.6.1", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-stream": "^4.5.25", "tslib": "^2.6.2" } }, "sha512-DPoGWfy7J7RKxvbf5kOKIGQkD2ek3dbKgzKIGrnLuvZBz5myU+Im/H6pmc14QcnFbqHMqxvtWSgRDSJW3qXLQg=="],
"@aws-sdk/credential-provider-http": ["@aws-sdk/credential-provider-http@3.972.41", "", { "dependencies": { "@aws-sdk/core": "^3.974.13", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/fetch-http-handler": "^5.4.3", "@smithy/node-http-handler": "^4.7.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-IA3CQTjtJkb6u1H4mE4936c8OPBMa9Jggtwe8U2Mqw/vvb/tZ5Ebd0mcZcX0uKWQhOyYo/+qNIwkV5Xh+FeJJA=="],
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/credential-provider-env": "^3.972.34", "@aws-sdk/credential-provider-http": "^3.972.36", "@aws-sdk/credential-provider-login": "^3.972.38", "@aws-sdk/credential-provider-process": "^3.972.34", "@aws-sdk/credential-provider-sso": "^3.972.38", "@aws-sdk/credential-provider-web-identity": "^3.972.38", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/credential-provider-imds": "^4.2.14", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-oDzUBu2MGJFgoar05sPMCwSrhw44ASyccrHzj66vO69OZqi7I6hZZxXfuPLC8OCzW7C+sU+bI73XHij41yekgQ=="],
"@aws-sdk/credential-provider-ini": ["@aws-sdk/credential-provider-ini@3.972.43", "", { "dependencies": { "@aws-sdk/core": "^3.974.13", "@aws-sdk/credential-provider-env": "^3.972.39", "@aws-sdk/credential-provider-http": "^3.972.41", "@aws-sdk/credential-provider-login": "^3.972.43", "@aws-sdk/credential-provider-process": "^3.972.39", "@aws-sdk/credential-provider-sso": "^3.972.43", "@aws-sdk/credential-provider-web-identity": "^3.972.43", "@aws-sdk/nested-clients": "^3.997.11", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-4mzII+3mZEVXXE1xzrLQrCJL7/r62A63bA6SVzZoNL5rqCJghpf+xgGltVrIBBs0n+mOZBKrQl2tRREtvZ5l6A=="],
"@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/protocol-http": "^5.3.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-g1NosS8qe4OF++G2UFCM5ovSkgipC7YYor5KCWatG0UoMSO5YFj9C8muePlyVmOBV/WTI16Jo3/s1NUo/o1Bww=="],
"@aws-sdk/credential-provider-login": ["@aws-sdk/credential-provider-login@3.972.43", "", { "dependencies": { "@aws-sdk/core": "^3.974.13", "@aws-sdk/nested-clients": "^3.997.11", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-HG7kQCwXtbv3oBV61Ins0oNX8KKyvrMqqRkb6ZiAfQHbMuHaiNaEb2KnpKLPkNpqImSBK82UkVE/kaY6IfWikA=="],
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.39", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.34", "@aws-sdk/credential-provider-http": "^3.972.36", "@aws-sdk/credential-provider-ini": "^3.972.38", "@aws-sdk/credential-provider-process": "^3.972.34", "@aws-sdk/credential-provider-sso": "^3.972.38", "@aws-sdk/credential-provider-web-identity": "^3.972.38", "@aws-sdk/types": "^3.973.8", "@smithy/credential-provider-imds": "^4.2.14", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-HEswDQyxUtadoZ/bJsPPENHg7R0Lzym5LuMksJeHvqhCOpP+rtkDLKI4/ZChH4w3cf5kG8n6bZuI8PzajoiqMg=="],
"@aws-sdk/credential-provider-node": ["@aws-sdk/credential-provider-node@3.972.44", "", { "dependencies": { "@aws-sdk/credential-provider-env": "^3.972.39", "@aws-sdk/credential-provider-http": "^3.972.41", "@aws-sdk/credential-provider-ini": "^3.972.43", "@aws-sdk/credential-provider-process": "^3.972.39", "@aws-sdk/credential-provider-sso": "^3.972.43", "@aws-sdk/credential-provider-web-identity": "^3.972.43", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-sDaBIT0yrNNIPfvlsiTCmANm07zKju+ipWODjEXgZlsjMeIJR3LVp7RDyAOzUoAsTbDfYKDWp+i5WrFiQP6rmQ=="],
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.34", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-T3IFs4EVmVi1dVN5RciFnklCANSzvrQd/VuHY9ThHSQmYkTogjcGkoJEr+oNUPQZnso52183088NqysMPji1/Q=="],
"@aws-sdk/credential-provider-process": ["@aws-sdk/credential-provider-process@3.972.39", "", { "dependencies": { "@aws-sdk/core": "^3.974.13", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-2k/amBifLd75eXNwgvPw/2lKYSQ3NhvHQgkVKVjfUq13/eJ3JRtHmznuFenn74OK3sSfp4SMy1YB2w+UVXoKqA=="],
"@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/token-providers": "3.1041.0", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-5ZxG+t0+3Q3QPh8KEjX6syskhgNf7I0MN7oGioTf6Lm1NTjfP7sIcYGNsthXC2qR8vcD3edNZwCr2ovfSSWuRA=="],
"@aws-sdk/credential-provider-sso": ["@aws-sdk/credential-provider-sso@3.972.43", "", { "dependencies": { "@aws-sdk/core": "^3.974.13", "@aws-sdk/nested-clients": "^3.997.11", "@aws-sdk/token-providers": "3.1052.0", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-LPc3+Y4vhH1T4x6CMqwCM6hk5+SRf/Lwmgm8INm95wxTtIRHcMwQUVkDzWu4Iw/RSncxYM2BC01OrYbxOPZvyg=="],
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-lYHFF30DGI20jZcYX8cm6Ns0V7f1dDN6g/MBDLTyD/5iw+bXs3yBr2iAiHDkx4RFU5JgsnZvCHYKiRVPRdmOgw=="],
"@aws-sdk/credential-provider-web-identity": ["@aws-sdk/credential-provider-web-identity@3.972.43", "", { "dependencies": { "@aws-sdk/core": "^3.974.13", "@aws-sdk/nested-clients": "^3.997.11", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-wQtL34lUD/09VXjwAUo2T+I3aEXRDxMB3DKmTJL/Zj0Gi6sLDTrVhae1XVt01yzkquOWajI/sZW72JGDZ1ciTw=="],
"@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.1045.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.1045.0", "@aws-sdk/core": "^3.974.8", "@aws-sdk/credential-provider-cognito-identity": "^3.972.31", "@aws-sdk/credential-provider-env": "^3.972.34", "@aws-sdk/credential-provider-http": "^3.972.36", "@aws-sdk/credential-provider-ini": "^3.972.38", "@aws-sdk/credential-provider-login": "^3.972.38", "@aws-sdk/credential-provider-node": "^3.972.39", "@aws-sdk/credential-provider-process": "^3.972.34", "@aws-sdk/credential-provider-sso": "^3.972.38", "@aws-sdk/credential-provider-web-identity": "^3.972.38", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/config-resolver": "^4.4.17", "@smithy/core": "^3.23.17", "@smithy/credential-provider-imds": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/property-provider": "^4.2.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-J+it58HUGyMIAquB6pWtvmO4m0E/gQ/Tz9Xcoogk3Rety13likU5U8HioeIgE+aN1DDOAB//MARoIdLZS1Mpfw=="],
"@aws-sdk/credential-providers": ["@aws-sdk/credential-providers@3.1053.0", "", { "dependencies": { "@aws-sdk/client-cognito-identity": "3.1053.0", "@aws-sdk/core": "^3.974.13", "@aws-sdk/credential-provider-cognito-identity": "^3.972.36", "@aws-sdk/credential-provider-env": "^3.972.39", "@aws-sdk/credential-provider-http": "^3.972.41", "@aws-sdk/credential-provider-ini": "^3.972.43", "@aws-sdk/credential-provider-login": "^3.972.43", "@aws-sdk/credential-provider-node": "^3.972.44", "@aws-sdk/credential-provider-process": "^3.972.39", "@aws-sdk/credential-provider-sso": "^3.972.43", "@aws-sdk/credential-provider-web-identity": "^3.972.43", "@aws-sdk/nested-clients": "^3.997.11", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/credential-provider-imds": "^4.3.2", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-jMzNBhYIIzaKiVOFndhyWSvEIosiU/zSxgcOaGXrHGcwlRXcFgTgZEcOFL504hxg4BdrrAIVdGw55Zk9zMhs7g=="],
"@aws-sdk/middleware-host-header": ["@aws-sdk/middleware-host-header@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-IJSsIMeVQ8MMCPbuh1AbltkFhLBLXn7aejzfX5YKT/VLDHn++Dcz8886tXckE+wQssyPUhaXrJhdakO2VilRhg=="],
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.11", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.13", "@aws-sdk/signature-v4-multi-region": "^3.996.28", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/fetch-http-handler": "^5.4.3", "@smithy/node-http-handler": "^4.7.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-nWXXJ1r/r8N2Gw1pWolRgED38/A9A8DHR2ETWIv220zh4PZHcybbR4hUVWWktmNXTRHzDJwRluapHn0rZxuoqA=="],
"@aws-sdk/middleware-logger": ["@aws-sdk/middleware-logger@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-OOuGvvz1Dm20SjZo5oEBePFqxt5nf8AwkNDSyUHvD9/bfNASmstcYxFAHUowy4n6Io7mWUZ04JURZwSBvyQanQ=="],
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.28", "", { "dependencies": { "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/signature-v4": "^5.4.2", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-qs9z5LqXO/CZC2Lg9SGKpoLU8Rhi+m2pFKZqfO9pytX1clc0katqtsDNupJxFy0xT9wsZSPzM2v1y+/H/zfp5Q=="],
"@aws-sdk/middleware-recursion-detection": ["@aws-sdk/middleware-recursion-detection@3.972.11", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@aws/lambda-invoke-store": "^0.2.2", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-+zz6f79Kj9V5qFK2P+D8Ehjnw4AhphAlCAsPjUqEcInA9umtSSKMrHbSagEeOIsDNuvVrH98bjRHcyQukTrhaQ=="],
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1052.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.13", "@aws-sdk/nested-clients": "^3.997.11", "@aws-sdk/types": "^3.973.9", "@smithy/core": "^3.24.3", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-QqZNB3so7UIDxZtroc85TQaLVxdZRFm0eWM1CSR2N+b06as9TOrilvrlTZuj3guYlxMs6yLOgGxnklJ5qMYtTw=="],
"@aws-sdk/middleware-sdk-s3": ["@aws-sdk/middleware-sdk-s3@3.972.37", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-arn-parser": "^3.972.3", "@smithy/core": "^3.23.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-stream": "^4.5.25", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-Km7M+i8DrLArVzrid1gfxeGhYHBd3uxvE77g0s5a52zPSVosxzQBnJ0gwWb6NIp/DOk8gsBMhi7V+cpJG0ndTA=="],
"@aws-sdk/middleware-user-agent": ["@aws-sdk/middleware-user-agent@3.972.38", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.8", "@smithy/core": "^3.23.17", "@smithy/protocol-http": "^5.3.14", "@smithy/types": "^4.14.1", "@smithy/util-retry": "^4.3.6", "tslib": "^2.6.2" } }, "sha512-iz+B29TXcAZsJpwB+AwG/TTGA5l/VnmMZ2UxtiySOZjI6gCdmviXPwdgzcmuazMy16rXoPY4mYCGe7zdNKfx5A=="],
"@aws-sdk/nested-clients": ["@aws-sdk/nested-clients@3.997.6", "", { "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", "@aws-sdk/core": "^3.974.8", "@aws-sdk/middleware-host-header": "^3.972.10", "@aws-sdk/middleware-logger": "^3.972.10", "@aws-sdk/middleware-recursion-detection": "^3.972.11", "@aws-sdk/middleware-user-agent": "^3.972.38", "@aws-sdk/region-config-resolver": "^3.972.13", "@aws-sdk/signature-v4-multi-region": "^3.996.25", "@aws-sdk/types": "^3.973.8", "@aws-sdk/util-endpoints": "^3.996.8", "@aws-sdk/util-user-agent-browser": "^3.972.10", "@aws-sdk/util-user-agent-node": "^3.973.24", "@smithy/config-resolver": "^4.4.17", "@smithy/core": "^3.23.17", "@smithy/fetch-http-handler": "^5.3.17", "@smithy/hash-node": "^4.2.14", "@smithy/invalid-dependency": "^4.2.14", "@smithy/middleware-content-length": "^4.2.14", "@smithy/middleware-endpoint": "^4.4.32", "@smithy/middleware-retry": "^4.5.7", "@smithy/middleware-serde": "^4.2.20", "@smithy/middleware-stack": "^4.2.14", "@smithy/node-config-provider": "^4.3.14", "@smithy/node-http-handler": "^4.6.1", "@smithy/protocol-http": "^5.3.14", "@smithy/smithy-client": "^4.12.13", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-base64": "^4.3.2", "@smithy/util-body-length-browser": "^4.2.2", "@smithy/util-body-length-node": "^4.2.3", "@smithy/util-defaults-mode-browser": "^4.3.49", "@smithy/util-defaults-mode-node": "^4.2.54", "@smithy/util-endpoints": "^3.4.2", "@smithy/util-middleware": "^4.2.14", "@smithy/util-retry": "^4.3.6", "@smithy/util-utf8": "^4.2.2", "tslib": "^2.6.2" } }, "sha512-WBDnqatJl+kGObpfmfSxqnXeYTu3Me8wx8WCtvoxX3pfWrrTv8I4WTMSSs7PZqcRcVh8WeUKMgGFjMG+52SR1w=="],
"@aws-sdk/region-config-resolver": ["@aws-sdk/region-config-resolver@3.972.13", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/config-resolver": "^4.4.17", "@smithy/node-config-provider": "^4.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-CvJ2ZIjK/jVD/lbOpowBVElJyC1YxLTIJ13yM0AEo0t2v7swOzGjSA6lJGH+DwZXQhcjUjoYwc8bVYCX5MDr1A=="],
"@aws-sdk/signature-v4-multi-region": ["@aws-sdk/signature-v4-multi-region@3.996.25", "", { "dependencies": { "@aws-sdk/middleware-sdk-s3": "^3.972.37", "@aws-sdk/types": "^3.973.8", "@smithy/protocol-http": "^5.3.14", "@smithy/signature-v4": "^5.3.14", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-+CMIt3e1VzlklAECmG+DtP1sV8iKq25FuA0OKpnJ4KA0kxUtd7CgClY7/RU6VzJBQwbN4EJ9Ue6plvqx1qGadw=="],
"@aws-sdk/token-providers": ["@aws-sdk/token-providers@3.1041.0", "", { "dependencies": { "@aws-sdk/core": "^3.974.8", "@aws-sdk/nested-clients": "^3.997.6", "@aws-sdk/types": "^3.973.8", "@smithy/property-provider": "^4.2.14", "@smithy/shared-ini-file-loader": "^4.4.9", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-Th7kPI6YPtvJUcdznooXJMy+9rQWjmEF81LxaJssngBzuysK4a/x+l8kjm1zb7nYsUPbndnBdUnwng/3PLvtGw=="],
"@aws-sdk/types": ["@aws-sdk/types@3.973.8", "", { "dependencies": { "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw=="],
"@aws-sdk/util-arn-parser": ["@aws-sdk/util-arn-parser@3.972.3", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-HzSD8PMFrvgi2Kserxuff5VitNq2sgf3w9qxmskKDiDTThWfVteJxuCS9JXiPIPtmCrp+7N9asfIaVhBFORllA=="],
"@aws-sdk/util-endpoints": ["@aws-sdk/util-endpoints@3.996.8", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/types": "^4.14.1", "@smithy/url-parser": "^4.2.14", "@smithy/util-endpoints": "^3.4.2", "tslib": "^2.6.2" } }, "sha512-oOZHcRDihk5iEe5V25NVWg45b3qEA8OpHWVdU/XQh8Zj4heVPAJqWvMphQnU7LkufmUo10EpvFPZuQMiFLJK3g=="],
"@aws-sdk/types": ["@aws-sdk/types@3.973.9", "", { "dependencies": { "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-kuBfgQVdcz5Bmapc4A13YbpVw/pXkesfhetcFYwbntqas8sF41OHyd4o28+/TG2ZQdHBsv90Lsu5y6oitvYCdg=="],
"@aws-sdk/util-locate-window": ["@aws-sdk/util-locate-window@3.965.5", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ=="],
"@aws-sdk/util-user-agent-browser": ["@aws-sdk/util-user-agent-browser@3.972.10", "", { "dependencies": { "@aws-sdk/types": "^3.973.8", "@smithy/types": "^4.14.1", "bowser": "^2.11.0", "tslib": "^2.6.2" } }, "sha512-FAzqXvfEssGdSIz8ejatan0bOdx1qefBWKF/gWmVBXIP1HkS7v/wjjaqrAGGKvyihrXTXW00/2/1nTJtxpXz7g=="],
"@aws-sdk/util-user-agent-node": ["@aws-sdk/util-user-agent-node@3.973.24", "", { "dependencies": { "@aws-sdk/middleware-user-agent": "^3.972.38", "@aws-sdk/types": "^3.973.8", "@smithy/node-config-provider": "^4.3.14", "@smithy/types": "^4.14.1", "@smithy/util-config-provider": "^4.2.2", "tslib": "^2.6.2" }, "peerDependencies": { "aws-crt": ">=1.0.0" }, "optionalPeers": ["aws-crt"] }, "sha512-ZWwlkjcIp7cEL8ZfTpTAPNkwx25p7xol0xlKoWVVf22+nsjwmLcHYtTPjIV1cSpmB/b6DaK4cb1fSkvCXHgRdw=="],
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.22", "", { "dependencies": { "@nodable/entities": "2.1.0", "@smithy/types": "^4.14.1", "fast-xml-parser": "5.7.2", "tslib": "^2.6.2" } }, "sha512-PMYKKtJd70IsSG0yHrdAbxBr+ZWBKLvzFZfD3/urxgf6hXVMzuU5M+3MJ5G67RpOmLBu1fAUN65SbWuKUCOlAA=="],
"@aws-sdk/xml-builder": ["@aws-sdk/xml-builder@3.972.25", "", { "dependencies": { "@nodable/entities": "2.1.0", "@smithy/types": "^4.14.2", "fast-xml-parser": "5.7.3", "tslib": "^2.6.2" } }, "sha512-GH+Kjz4nPKWKHnsiQpnhP1MJdTGIcK4rAka6tzakgjjUkVgNsmPeEbbRAf09SzS1hjGu6duGHCBsxYke0BhHjQ=="],
"@aws/lambda-invoke-store": ["@aws/lambda-invoke-store@0.2.4", "", {}, "sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ=="],
@@ -551,9 +542,9 @@
"@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="],
"@base-ui/react": ["@base-ui/react@1.4.1", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@base-ui/utils": "0.2.8", "@floating-ui/react-dom": "^2.1.8", "@floating-ui/utils": "^0.2.11", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@date-fns/tz": "^1.2.0", "@types/react": "^17 || ^18 || ^19", "date-fns": "^4.0.0", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@date-fns/tz", "@types/react", "date-fns"] }, "sha512-Ab5/LIhcmL8BQcsBUYiOfkSDRdLpvgUBzMK30cu684JPcLclYlztharvCZyNNgzJtbAiREzI9q0pI5erHCMgCw=="],
"@base-ui/react": ["@base-ui/react@1.5.0", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@base-ui/utils": "0.2.9", "@floating-ui/react-dom": "^2.1.8", "@floating-ui/utils": "^0.2.11", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@date-fns/tz": "^1.2.0", "@types/react": "^17 || ^18 || ^19", "date-fns": "^4.0.0", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@date-fns/tz", "@types/react", "date-fns"] }, "sha512-z1gSAlced1yY+iM+mHDEtIkD8UI3Ebs52MuBPxvV6f5hRutk+xvCH/wuB7hDqDzK9JG5FoMz5nhrqtSs1wjt1A=="],
"@base-ui/utils": ["@base-ui/utils@0.2.8", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.11", "reselect": "^5.1.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-jvOi+c+ftGlGotNcKnzPVg2IhCaDTB6/6R3JeqdjdXktuAJi3wKH9T7+svuaKh1mmfVU11UWzUZVH74JDfi/wQ=="],
"@base-ui/utils": ["@base-ui/utils@0.2.9", "", { "dependencies": { "@babel/runtime": "^7.29.2", "@floating-ui/utils": "^0.2.11", "reselect": "^5.1.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { "@types/react": "^17 || ^18 || ^19", "react": "^17 || ^18 || ^19", "react-dom": "^17 || ^18 || ^19" }, "optionalPeers": ["@types/react"] }, "sha512-x/PDDCYzoqPpjrdyb3VcyylTI2IjUXEtYDGi5foh7KsnmNJIIaVwA2GLgDH1dps1GgXiJbA60hM+AyuTfQzIvw=="],
"@biomejs/biome": ["@biomejs/biome@2.4.5", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.4.5", "@biomejs/cli-darwin-x64": "2.4.5", "@biomejs/cli-linux-arm64": "2.4.5", "@biomejs/cli-linux-arm64-musl": "2.4.5", "@biomejs/cli-linux-x64": "2.4.5", "@biomejs/cli-linux-x64-musl": "2.4.5", "@biomejs/cli-win32-arm64": "2.4.5", "@biomejs/cli-win32-x64": "2.4.5" }, "bin": { "biome": "bin/biome" } }, "sha512-OWNCyMS0Q011R6YifXNOg6qsOg64IVc7XX6SqGsrGszPbkVCoaO7Sr/lISFnXZ9hjQhDewwZ40789QmrG0GYgQ=="],
@@ -575,19 +566,19 @@
"@braintree/sanitize-url": ["@braintree/sanitize-url@7.1.2", "", {}, "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA=="],
"@chat-adapter/discord": ["@chat-adapter/discord@4.28.1", "", { "dependencies": { "@chat-adapter/shared": "4.28.1", "chat": "4.28.1", "discord-api-types": "^0.37.119", "discord-interactions": "^4.4.0", "discord.js": "^14.25.1" } }, "sha512-j9/mym6upfS0aIpc9TQSxHKZDBlIUz6kq8v9jduq1YuErV+a3bVqxLXBzHRtCQMmVBj89Zy8mH7jXkBavlth5A=="],
"@chat-adapter/discord": ["@chat-adapter/discord@4.29.0", "", { "dependencies": { "@chat-adapter/shared": "4.29.0", "chat": "4.29.0", "discord-api-types": "^0.37.119", "discord-interactions": "^4.4.0", "discord.js": "^14.25.1" } }, "sha512-C6pDVKn7s0PhvgeqldYxoShWXJzthwtlo+sCesqenh56M03eHsioinqxeJttmtK8y1ZD8/qiP2lAZufDwuEQhA=="],
"@chat-adapter/gchat": ["@chat-adapter/gchat@4.28.1", "", { "dependencies": { "@chat-adapter/shared": "4.28.1", "@googleapis/chat": "^44.6.0", "@googleapis/workspaceevents": "^9.1.0", "chat": "4.28.1" } }, "sha512-+S1JsooTc3cQJi8Es4bqC+a4segz0KiIIlYPlr6m4EZYB9mX+eT27Dxz3Ce5V6oAM6cFGLfRpR8gz4dwSkLq2w=="],
"@chat-adapter/gchat": ["@chat-adapter/gchat@4.29.0", "", { "dependencies": { "@chat-adapter/shared": "4.29.0", "@googleapis/chat": "^44.6.0", "@googleapis/workspaceevents": "^9.1.0", "chat": "4.29.0" } }, "sha512-SZ5ZgzFmZ4oRj0AAISbjPztPiICTpw+RdPiPywNwqGWt2LItUOL+8+dl8zZMk+F86E/r0sqRjdbc8+9GqUe2pA=="],
"@chat-adapter/linear": ["@chat-adapter/linear@4.28.1", "", { "dependencies": { "@chat-adapter/shared": "4.28.1", "@linear/sdk": "^76.0.0", "chat": "4.28.1" } }, "sha512-ZLcmb6lU26ZSJEwo6g8IyXUsTInBVPbqV72CQ0zGy9SyKs/xBUv8xftj6Q1UMIncaLLPbAa4vpjW6+zvCruZ4A=="],
"@chat-adapter/linear": ["@chat-adapter/linear@4.29.0", "", { "dependencies": { "@chat-adapter/shared": "4.29.0", "@linear/sdk": "^76.0.0", "chat": "4.29.0" } }, "sha512-4cq7pBv0CICka8V0uuae7bNfb1rTdmYjsNjOs7Gkr4vChlhDxRUEGUoiBqvOEYKqxFtFOkRk9Wod0tIQmbPySw=="],
"@chat-adapter/shared": ["@chat-adapter/shared@4.28.1", "", { "dependencies": { "chat": "4.28.1" } }, "sha512-v7AcZMrvS2gxFlRiUO1o9Nta2iipnnmV54Gie8e3nQTQvnghENfSf7j7nimA5DOUWCgj+e4DV7LE0x1pakNtkA=="],
"@chat-adapter/shared": ["@chat-adapter/shared@4.29.0", "", { "dependencies": { "chat": "4.29.0" } }, "sha512-ARqTDoHJHKN9rpytbFPJbNmqqx3fOg5xwsTZdlingQPAssOSeHDBdqrFJkgDhyCRGbmDtG09cuS0FkVzeoh2qg=="],
"@chat-adapter/slack": ["@chat-adapter/slack@4.28.1", "", { "dependencies": { "@chat-adapter/shared": "4.28.1", "@slack/socket-mode": "^2.0.5", "@slack/web-api": "^7.14.0", "chat": "4.28.1" } }, "sha512-JxgV7+cRXXeKpj0MzS7nzG3JvpnfhIgnPo9r/sdEIzeWhIb8tUcT2PbLl/fpSu/cb+WkICS0bCENn1I0PS39Hg=="],
"@chat-adapter/slack": ["@chat-adapter/slack@4.29.0", "", { "dependencies": { "@chat-adapter/shared": "4.29.0", "@slack/socket-mode": "^2.0.5", "@slack/web-api": "^7.14.0", "chat": "4.29.0" } }, "sha512-s2DXAwkTpmiIKSATXgrO879s1pqFwS70Y0JPd+TRGRzDeh6nfqt5dnKt5Bug0P1zwkB6DoPurhnYS9nqhSmD/w=="],
"@chat-adapter/telegram": ["@chat-adapter/telegram@4.28.1", "", { "dependencies": { "@chat-adapter/shared": "4.28.1", "chat": "4.28.1" } }, "sha512-ZBw6zx36enxXGlbOoigzCsWH6slbTCOWyTGatCz7jq4DFTDpvjRgBBH760n9peFkZpXJWOAXZKJm/IW8saT5aw=="],
"@chat-adapter/telegram": ["@chat-adapter/telegram@4.29.0", "", { "dependencies": { "@chat-adapter/shared": "4.29.0", "chat": "4.29.0" } }, "sha512-015tU3HEjFQWw7DgebXWkDeQA6lTdTVEO4btAV3f6U1kEnOfjLVJq98latcsM1WkEvv+3LIFKpsz9pG53aamBw=="],
"@chat-adapter/whatsapp": ["@chat-adapter/whatsapp@4.28.1", "", { "dependencies": { "@chat-adapter/shared": "4.28.1", "chat": "4.28.1" } }, "sha512-NSU4Yda/uhbZXQNBnIgDHFWN+3ZBJ7L7mrFHUIctwZBX1XHlGkweWucfFbDynWgxb4IDm6NYZxA34+HVe8ugBA=="],
"@chat-adapter/whatsapp": ["@chat-adapter/whatsapp@4.29.0", "", { "dependencies": { "@chat-adapter/shared": "4.29.0", "chat": "4.29.0" } }, "sha512-CDKmlDHmiiJ2xtca0wZ2DIYnySUFuiKn6f3ZQvschFVa6pSaDmaldmJc3iul+ELi10+RE7x5+immfc//+TTzFg=="],
"@chevrotain/types": ["@chevrotain/types@11.1.2", "", {}, "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw=="],
@@ -605,6 +596,8 @@
"@cline/example-cli-agent": ["@cline/example-cli-agent@workspace:apps/examples/cli-agent"],
"@cline/example-cline-core-cli-agent": ["@cline/example-cline-core-cli-agent@workspace:apps/examples/cline-core-cli-agent"],
"@cline/example-code-review-bot": ["@cline/example-code-review-bot@workspace:apps/examples/code-review-bot"],
"@cline/example-multi-agent": ["@cline/example-multi-agent@workspace:apps/examples/multi-agent"],
@@ -621,7 +614,7 @@
"@cline/vscode": ["@cline/vscode@workspace:apps/examples/vscode"],
"@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="],
"@date-fns/tz": ["@date-fns/tz@1.5.0", "", {}, "sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg=="],
"@dimforge/rapier2d-simd-compat": ["@dimforge/rapier2d-simd-compat@0.17.3", "", {}, "sha512-bijvwWz6NHsNj5e5i1vtd3dU2pDhthSaTUZSh14DUGGKJfw8eMnlWZsxwHBxB/a3AXVNDjL9abuHw1k9FGR+jg=="],
@@ -637,7 +630,7 @@
"@discordjs/ws": ["@discordjs/ws@1.2.3", "", { "dependencies": { "@discordjs/collection": "^2.1.0", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", "discord-api-types": "^0.38.1", "tslib": "^2.6.2", "ws": "^8.17.0" } }, "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw=="],
"@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.65.0", "", { "dependencies": { "commander": "^11.1.0", "dotenv": "^17.2.1", "eciesjs": "^0.4.10", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "picomatch": "^4.0.4", "which": "^4.0.0", "yocto-spinner": "^1.1.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-v4FA/Lw3pTEloLxBqTOaYDX6MNo0Jo7lGBsPZhwnJBqRJp0AzQg1ZZNxrFsh6HVC6QWeWrfIKLn0y2eyIXaVDg=="],
"@dotenvx/dotenvx": ["@dotenvx/dotenvx@1.67.0", "", { "dependencies": { "commander": "^11.1.0", "dotenv": "^17.2.1", "eciesjs": "^0.4.10", "enquirer": "^2.4.1", "execa": "^5.1.1", "fdir": "^6.2.0", "ignore": "^5.3.0", "object-treeify": "1.1.33", "picomatch": "^4.0.4", "which": "^4.0.0", "yocto-spinner": "^1.1.0" }, "bin": { "dotenvx": "src/cli/dotenvx.js" } }, "sha512-KBfIx5OrAG6giqSkHCkQWynZmT47XkSTuuYIcvjHxlKoVRlYbxNrJmyIPaefnszU8MCvMwrrB+viJQzPqzgpcg=="],
"@ecies/ciphers": ["@ecies/ciphers@0.2.6", "", { "peerDependencies": { "@noble/ciphers": "^1.0.0" } }, "sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g=="],
@@ -725,11 +718,11 @@
"@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="],
"@fontsource-variable/geist": ["@fontsource-variable/geist@5.2.8", "", {}, "sha512-cJ6m9e+8MQ5dCYJsLylfZrgBh6KkG4bOLckB35Tr9J/EqdkEM6QllH5PxqP1dhTvFup+HtMRPuz9xOjxXJggxw=="],
"@fontsource-variable/geist": ["@fontsource-variable/geist@5.2.9", "", {}, "sha512-TP+QSBG3wxKGPE33CbMy/L0Nu3qvJ6Fy81Yc4LnQ95xH+i+cfEp8fyU8/kfV14YwszxIFPhnoMTbjL71waVpyQ=="],
"@googleapis/chat": ["@googleapis/chat@44.6.0", "", { "dependencies": { "googleapis-common": "^8.0.0" } }, "sha512-Bnqzev/bSTXSbE0/N2WS4Stnleo8j9bJJ1LkCBk1fXQnehcArVMv7q543rzPYU6MJql4D34On6diNGAuYtI9xQ=="],
"@googleapis/chat": ["@googleapis/chat@44.7.0", "", { "dependencies": { "googleapis-common": "^8.0.0" } }, "sha512-1TTvtQ/nRD4Yb5PcMWl1J6vN3QjOyDr3t9XtM1iRJlAO8wux5dOChJSOyAlm2IOcRrrqmL4d0DVUkgMqovHjNA=="],
"@googleapis/workspaceevents": ["@googleapis/workspaceevents@9.1.0", "", { "dependencies": { "googleapis-common": "^8.0.0" } }, "sha512-aJiMrTi/YyUUaaTO0tnhTHDYU+N9CTD3l3FSfe0yzEHQl7DEc+1LISgdK1o2nurvCtguBEumify5kTkr6Cg5eA=="],
"@googleapis/workspaceevents": ["@googleapis/workspaceevents@9.2.0", "", { "dependencies": { "googleapis-common": "^8.0.0" } }, "sha512-9tU0h6O/Ao9k53TQSgLs6D/mN++wKTHPIpT8tbPaayhOL3e4OhtJ3t+OD42avMe2pBmFcdRUVOSpZvqytxvWEg=="],
"@gramio/format": ["@gramio/format@0.7.0", "", { "dependencies": { "@gramio/types": "^9.6.0" }, "peerDependencies": { "marked": "^15.0.11", "node-html-parser": ">=6.0.0" }, "optionalPeers": ["marked", "node-html-parser"] }, "sha512-+qLKopeQHU3dfnwtVd7smKqyJTEYbveAj0l3hfuVwzdCfTQFdBcJvM3hhhTIcchlhUpPx7znKzw1+Vrq0GCNyg=="],
@@ -947,21 +940,21 @@
"@open-draft/until": ["@open-draft/until@2.1.0", "", {}, "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg=="],
"@openai/codex": ["@openai/codex@0.105.0", "", { "optionalDependencies": { "@openai/codex-darwin-arm64": "npm:@openai/codex@0.105.0-darwin-arm64", "@openai/codex-darwin-x64": "npm:@openai/codex@0.105.0-darwin-x64", "@openai/codex-linux-arm64": "npm:@openai/codex@0.105.0-linux-arm64", "@openai/codex-linux-x64": "npm:@openai/codex@0.105.0-linux-x64", "@openai/codex-win32-arm64": "npm:@openai/codex@0.105.0-win32-arm64", "@openai/codex-win32-x64": "npm:@openai/codex@0.105.0-win32-x64" }, "bin": { "codex": "bin/codex.js" } }, "sha512-enoNmQs3aOgUhsKYC6kfuKEG0AogS4q01pqcySPwf9zl2r8OcKuMUoLw1v5n4Y7sd3B6qGS7UtTABqbcT5FaMA=="],
"@openai/codex": ["@openai/codex@0.130.0", "", { "optionalDependencies": { "@openai/codex-darwin-arm64": "npm:@openai/codex@0.130.0-darwin-arm64", "@openai/codex-darwin-x64": "npm:@openai/codex@0.130.0-darwin-x64", "@openai/codex-linux-arm64": "npm:@openai/codex@0.130.0-linux-arm64", "@openai/codex-linux-x64": "npm:@openai/codex@0.130.0-linux-x64", "@openai/codex-win32-arm64": "npm:@openai/codex@0.130.0-win32-arm64", "@openai/codex-win32-x64": "npm:@openai/codex@0.130.0-win32-x64" }, "bin": { "codex": "bin/codex.js" } }, "sha512-WGDj+RZ3TXWC/7MlwprgLWOqzpwatPIINPhP3IRzHA0ni+o3QZ4i4xrS2uWwGmHUJ395J5JHwoZAAZYyfJyz6w=="],
"@openai/codex-darwin-arm64": ["@openai/codex@0.105.0-darwin-arm64", "", { "os": "darwin", "cpu": "arm64" }, "sha512-9TD7pDIg8o7itmOhyEPcC2HeVnVIOxxrrbwTvnTibMj2rHPLnY8E0JaK8QOBRNiIUlqI4WKspTMUZQg5Fegndw=="],
"@openai/codex-darwin-arm64": ["@openai/codex@0.130.0-darwin-arm64", "", { "os": "darwin", "cpu": "arm64" }, "sha512-R9pkGC7kwC8yQ8el5hvBlmugQlcsG/pHMEFgZluu03X9fD2TezGxdq3KqRDRCZuMYl07ILamVEoqknuJ0cq7MA=="],
"@openai/codex-darwin-x64": ["@openai/codex@0.105.0-darwin-x64", "", { "os": "darwin", "cpu": "x64" }, "sha512-00xRV2X7RwKFRY8LB99/WmVSWqhHnMV6BB4gc5x4MMuDPDslaNrGTYWdp6KBukok1ayrg0JfwazUeAawNWU5Zw=="],
"@openai/codex-darwin-x64": ["@openai/codex@0.130.0-darwin-x64", "", { "os": "darwin", "cpu": "x64" }, "sha512-gJ+7J8djevgtdra+NgDAiQQPW+O3KTsgGfE3E5dpDfww3zS5OCeV0V2dhxqnJdlOjOSDw99o0P2LqBv19mhpRw=="],
"@openai/codex-linux-arm64": ["@openai/codex@0.105.0-linux-arm64", "", { "os": "linux", "cpu": "arm64" }, "sha512-UFGyZhRB0Gtr31wFf0WDd//W3XGbZZ7mxYwf528i6rhlwabb3FIJKWrgv4DVXKQZCGiBujqAk0pr32PziElouA=="],
"@openai/codex-linux-arm64": ["@openai/codex@0.130.0-linux-arm64", "", { "os": "linux", "cpu": "arm64" }, "sha512-tFtH0V9/hEI3d9y7zP92BXI9FM4Z3+STNQaOR52Czv18TRtCFUp7CbIUYaToopuq6UBfnE1VKr8RLhwT5FcbmA=="],
"@openai/codex-linux-x64": ["@openai/codex@0.105.0-linux-x64", "", { "os": "linux", "cpu": "x64" }, "sha512-cZgNzNjspqHmXNf/CraqqQrfotw5cXO7wvkSSYs2NZjZR7Ud10u5hFeumUW1sEvb5/F9tEKsjO+WCj+bVxdrYQ=="],
"@openai/codex-linux-x64": ["@openai/codex@0.130.0-linux-x64", "", { "os": "linux", "cpu": "x64" }, "sha512-3VcNlez99xdnEf+kB1IOpWv9fICYV9PiGj4sLCO4TCcShLnyxe+YBGa3poknkvXLnMG0qiN9SMnYS2FGrMxQcA=="],
"@openai/codex-win32-arm64": ["@openai/codex@0.105.0-win32-arm64", "", { "os": "win32", "cpu": "arm64" }, "sha512-OGvHTn/XAyY8889n0ZEcvUgiaPeT/rLFEFUEOzWgt5yhKiODV+zEzfruYmcvZUpzgFJ1kRQlDgKPMbW7u2r01Q=="],
"@openai/codex-win32-arm64": ["@openai/codex@0.130.0-win32-arm64", "", { "os": "win32", "cpu": "arm64" }, "sha512-vdpmiNp57L/arZabltLXn8TyEtNa7W1meOEkr+3R6W/8ZyBt++wuqz1Orv134OT2grrcFJsIVCAIPiqUxCvBkA=="],
"@openai/codex-win32-x64": ["@openai/codex@0.105.0-win32-x64", "", { "os": "win32", "cpu": "x64" }, "sha512-8V26RjFeg06i4mrrhQTKLY6lcRXsm0s1cxT3lamApLccvBBAhhAOE0je6jHb5nkrncvf9x/lee+WmY0louvvGQ=="],
"@openai/codex-win32-x64": ["@openai/codex@0.130.0-win32-x64", "", { "os": "win32", "cpu": "x64" }, "sha512-FzMznm7fr5/nbjZgOujZ9Y9AbdGm7ji1FOoWiY3U+srqauvZaTgn6o6aCheSL7kuymu7nTLOO/cAyWV6NuesqQ=="],
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.14.48", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-wKM86jCzV/ZApyWrdm3uP8XdWcS0LMbu3FV+OWz1ChiGGg1wiIWNGMJs5CY8/QX2/rUuZrd1Q1DqvdamZ0zLeg=="],
"@opencode-ai/sdk": ["@opencode-ai/sdk@1.15.8", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-e6O78KooMK3o5kZeUO1MQbzRt3W0fmQkE2ZdVRE50s10kBHrOavEeAEwUhFMaH8z2TZV/59az98nUlBLAE+wzA=="],
"@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
@@ -1011,7 +1004,7 @@
"@opentui/react": ["@opentui/react@0.1.102", "", { "dependencies": { "@opentui/core": "0.1.102", "react-reconciler": "^0.32.0" }, "peerDependencies": { "react": ">=19.0.0", "react-devtools-core": "^7.0.1", "ws": "^8.18.0" } }, "sha512-c7EiK30xlvaHc6WBOLAH7TJ8xC4QbiD5ZA6tb4zZ74XM4SH5Tb+uBee8b4TztTLseq+hGtW85qrIUJM3OrdtNw=="],
"@oxc-project/types": ["@oxc-project/types@0.129.0", "", {}, "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg=="],
"@oxc-project/types": ["@oxc-project/types@0.132.0", "", {}, "sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ=="],
"@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="],
@@ -1023,13 +1016,13 @@
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.5", "", {}, "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g=="],
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.1", "", {}, "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg=="],
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1" } }, "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw=="],
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.1", "", {}, "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew=="],
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.2", "", {}, "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw=="],
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
@@ -1157,41 +1150,41 @@
"@radix-ui/rect": ["@radix-ui/rect@1.1.1", "", {}, "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw=="],
"@rive-app/react-webgl2": ["@rive-app/react-webgl2@4.28.4", "", { "dependencies": { "@rive-app/webgl2": "2.37.6" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0" } }, "sha512-OeUAmHQjhqYza2zcpd7wctF3JxBNLCPQORYRIlZkGN1Tzcy7XF4ctyy7d0SAObW2vfS7+NWcTf9owoCzx5uehQ=="],
"@rive-app/react-webgl2": ["@rive-app/react-webgl2@4.28.6", "", { "dependencies": { "@rive-app/webgl2": "2.37.8" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0" } }, "sha512-QqtlD7bm01SxMLuEHE/BfhiPoX3RZ2/B32nF0IR0IRPe2ykxMeebWPtsX50AL9EKLbOh3Fgk3PJ7smkkvQwD2w=="],
"@rive-app/webgl2": ["@rive-app/webgl2@2.37.6", "", {}, "sha512-ZvUgD8yleilzqu0DuQF2r9bFOk+id1cmgSE/4QayyNGlqUTgANcKs2Ft78F27qeGLO06SE589ugrdgZLtL4kbw=="],
"@rive-app/webgl2": ["@rive-app/webgl2@2.37.8", "", {}, "sha512-Y2nXPwAeQtZrADNIzY7v3Lk7XZRMy4Gd+bpGFyzkaQ/EQ91Hp/6sCdd8yTCyjH4b71N/T6kU0MHIYA0IDmpjyQ=="],
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0", "", { "os": "android", "cpu": "arm64" }, "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA=="],
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.2", "", { "os": "android", "cpu": "arm64" }, "sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ=="],
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew=="],
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w=="],
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ=="],
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA=="],
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ=="],
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA=="],
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0", "", { "os": "linux", "cpu": "arm" }, "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A=="],
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.2", "", { "os": "linux", "cpu": "arm" }, "sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w=="],
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ=="],
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig=="],
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA=="],
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw=="],
"@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg=="],
"@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA=="],
"@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA=="],
"@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ=="],
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA=="],
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ=="],
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw=="],
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.2", "", { "os": "linux", "cpu": "x64" }, "sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw=="],
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0", "", { "os": "none", "cpu": "arm64" }, "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig=="],
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.2", "", { "os": "none", "cpu": "arm64" }, "sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w=="],
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg=="],
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.2", "", { "dependencies": { "@emnapi/core": "1.10.0", "@emnapi/runtime": "1.10.0", "@napi-rs/wasm-runtime": "^1.1.4" }, "cpu": "none" }, "sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ=="],
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow=="],
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A=="],
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0", "", { "os": "win32", "cpu": "x64" }, "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg=="],
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.2", "", { "os": "win32", "cpu": "x64" }, "sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.7", "", {}, "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA=="],
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.1", "", {}, "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw=="],
"@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="],
@@ -1201,19 +1194,19 @@
"@sec-ant/readable-stream": ["@sec-ant/readable-stream@0.4.1", "", {}, "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg=="],
"@shikijs/core": ["@shikijs/core@4.0.2", "", { "dependencies": { "@shikijs/primitive": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw=="],
"@shikijs/core": ["@shikijs/core@4.1.0", "", { "dependencies": { "@shikijs/primitive": "4.1.0", "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "sha512-jLJtSJeuFffqX6/inRE1zqU5aFv2hrszvYgq3OjbAgFRZiWv7abKMDdQzYxuSDfmUPQozZvI/kuy6VMTvnvqTQ=="],
"@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag=="],
"@shikijs/engine-javascript": ["@shikijs/engine-javascript@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.6" } }, "sha512-YquhawCUgaBfhsS72e2Y/dI59gCBNPHu3fEO/tvLaXrTssxZrY5ddjtNLTwndrMgPo8b3IscE+xoICDzpTmlFQ=="],
"@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg=="],
"@shikijs/engine-oniguruma": ["@shikijs/engine-oniguruma@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "sha512-axLpjVs45YBvvINa+dJF+NPW+KtFkNXsFr4SDw2BMj9GdeMnGxVB9PQb2xXlJYovslt/nz6giedAyOANkfc7hg=="],
"@shikijs/langs": ["@shikijs/langs@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg=="],
"@shikijs/langs": ["@shikijs/langs@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0" } }, "sha512-nwOMruEkbgdZfQ/b8CgpNBVOpvG1k0N5tbmgiFeqsan401+x3ILqlzZJowSla4Agmq4hG2Uf2wh5jLTEhR8VSg=="],
"@shikijs/primitive": ["@shikijs/primitive@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw=="],
"@shikijs/primitive": ["@shikijs/primitive@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-zx2/2Uwj2q9X3KSyYREEhXO23xBw5WUhP4orK2lE4r+t9JGITmEe0JH+wPmJhqHpOT2bRRs6lAL945+LDvOAGw=="],
"@shikijs/themes": ["@shikijs/themes@4.0.2", "", { "dependencies": { "@shikijs/types": "4.0.2" } }, "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA=="],
"@shikijs/themes": ["@shikijs/themes@4.1.0", "", { "dependencies": { "@shikijs/types": "4.1.0" } }, "sha512-emCcTnUM7yO2wltYbaxm+yLvcCI4+h8XBKc4KmJ7EZUXoSGjcCHifkI//R4OFit9ewpg7H2/9tjOuXrT2v/Knw=="],
"@shikijs/types": ["@shikijs/types@4.0.2", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg=="],
"@shikijs/types": ["@shikijs/types@4.1.0", "", { "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-3EQWX54fMpniOrDblzAhiwiJwpiTMW6+B9DWyUd9ska483tbayFYuw47UxwuPknI31bKnySfVQ/QW+jFL4rFdA=="],
"@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="],
@@ -1231,75 +1224,27 @@
"@slack/types": ["@slack/types@2.21.1", "", {}, "sha512-I8vmSjNYWsaxuWPx6dz4yeh0h7vRBWbgAMK14LEmblbZ404BtrPbXs6jDPx4cYgGf8msDGF4A9opLZBu21FViQ=="],
"@slack/web-api": ["@slack/web-api@7.15.2", "", { "dependencies": { "@slack/logger": "^4.0.1", "@slack/types": "^2.21.0", "@types/node": ">=18", "@types/retry": "0.12.0", "axios": "^1.15.0", "eventemitter3": "^5.0.1", "form-data": "^4.0.4", "is-electron": "2.2.2", "is-stream": "^2", "p-queue": "^6", "p-retry": "^4", "retry": "^0.13.1" } }, "sha512-/m9qVFkiq85Oa/FSQwYIRDa/AO4qNYkDh4sRBK1WqEc2+RyG7w4tbU6rBIwUOcc/TmWOIr24Nraquxg7um5mYw=="],
"@slack/web-api": ["@slack/web-api@7.16.0", "", { "dependencies": { "@slack/logger": "^4.0.1", "@slack/types": "^2.21.0", "@types/node": ">=18", "@types/retry": "0.12.0", "axios": "^1.16.0", "eventemitter3": "^5.0.1", "form-data": "^4.0.4", "is-electron": "2.2.2", "is-stream": "^2", "p-queue": "^6", "p-retry": "^4", "retry": "^0.13.1" } }, "sha512-68SAV77uuGKuhyyaRytX8UijVnqSLsTSKslGXw17cjQYXn+jtNl7gbaEjHgC5x2rhCuFdahBrEC2VCLppbzReg=="],
"@smithy/config-resolver": ["@smithy/config-resolver@4.5.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-abXk3LhODsvRHsk0ZS9ztrg/fZatTa9Z/z4pgx65YSLR+rY6kvUG/1IgcDKEUciR8MfdnkT5oPeHJTy/HhzDIQ=="],
"@smithy/core": ["@smithy/core@3.24.4", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-3UNRKEyQyAgVgM0LGlerCLm+ChZWZ1GPfde+jBEW6bm6bSBGU1p0EbblaUV3unbhwvidjLA5Zs3sOs7mnZwvAw=="],
"@smithy/core": ["@smithy/core@3.24.1", "", { "dependencies": { "@aws-crypto/crc32": "5.2.0", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-3mT7o4qQyUWttYnVK3A0Z/u3Xha3E81tXn32Tz6vjZiUXhBrkEivpw1hBYfh84iFF9CSzkBU9Y1DJ3Q6RQ231g=="],
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.3.4", "", { "dependencies": { "@smithy/core": "^3.24.4", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-vKW0MEFRU4Y3MkVZUkpJm+g9qyPGLCXhc0YLggUdSdBB4g7IaSSsCE75P9rBXyWHrXY1UYSQUl8/DwsTR7QciA=="],
"@smithy/credential-provider-imds": ["@smithy/credential-provider-imds@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-0S/acwHnqX4WrjXzhdiDRxsG2s9SC0cpPIK9nZ1R6UOHd+j7uL28+4bHu22urbLk2TVw3fkp6na/+fkUt/pLNQ=="],
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.3.4", "", { "dependencies": { "@smithy/core": "^3.24.4", "tslib": "^2.6.2" } }, "sha512-uI00gSvwvBEiVuqpHFcMPGXnVh1XQYuqlQREIX/GUmuwNNTdGRliUI8R71tbfwNLYP7t8E/HVqdohvjoWU13iA=="],
"@smithy/eventstream-codec": ["@smithy/eventstream-codec@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-yS8AiJM3Kf7LR+lZyUilUyjdJGksAqxfSC3C9k3d1OCrAvWjpMlsJ+rW9cIslZJM4AtWh2UAqgZUWTtMeMdtDQ=="],
"@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.4.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-r7bN6spQ+caZC8AnyvSxkRUb57zt2jhhRw3Z+2Ez8hjq6coIikDBFUUI/+CQ1xx9K6eX1Gx6wUKo4ylU66TIqw=="],
"@smithy/hash-node": ["@smithy/hash-node@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-u0/zo11mg7yNneoYgTkH4sXwSmcBpbl49o4UNCtQ7hYsXxynsN25KYHmXzqi7TPk5HQL5klGnpU5koOY0O+9hw=="],
"@smithy/invalid-dependency": ["@smithy/invalid-dependency@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-cLmwtDoulyZvRepAfyV+3rx5oMvuh51dbE+6En3vGC09j3uVSRt1U4oguNu32ub3soGX0oYtBs8E7S2Q4SxTqg=="],
"@smithy/fetch-http-handler": ["@smithy/fetch-http-handler@5.4.4", "", { "dependencies": { "@smithy/core": "^3.24.4", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-qM7AUKI4G6d7lNgaZD3lA1tWSolh5r6gcixfTZAPstVURfjIbvreVTPz+994M0yC3HbX4YYhDRgr31Xy3XwWOQ=="],
"@smithy/is-array-buffer": ["@smithy/is-array-buffer@2.2.0", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA=="],
"@smithy/middleware-content-length": ["@smithy/middleware-content-length@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-l4BUIP+wljW/Ar+0/QcGdmElI9lalrywfzNijXMBG34Z510FRzPyrDLx/blNTZOAm0C4Mvx5t/bf760CZo1ajg=="],
"@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.4", "", { "dependencies": { "@smithy/core": "^3.24.4", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-HIeF+1vrDGzPkkv39Hj2vlHSXHY3p958jd/8ZnePIY6+ZOsQX8coyEUKO5yQu4r0bQIVsbpotVIrXXwyycMStQ=="],
"@smithy/middleware-endpoint": ["@smithy/middleware-endpoint@4.5.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-qtqu5TS+8Y18ZDkJoiXN5AMW1G4JAg1+xytzpsUvIR5a4EUsgd5HQg12lekEHWpm2TDUmOgg+hBaHK7dvyWdkA=="],
"@smithy/signature-v4": ["@smithy/signature-v4@5.4.4", "", { "dependencies": { "@smithy/core": "^3.24.4", "@smithy/types": "^4.14.2", "tslib": "^2.6.2" } }, "sha512-e5UtkMvsatzBfbeBZjEOt0k0Z3BEsjTFL/n6fdO5vtBLe67tdy0dX7xw2DU7uZ3acwoHyeCqpU2Fzb7pxwHb6Q=="],
"@smithy/middleware-retry": ["@smithy/middleware-retry@4.6.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-eTaQhxs0rfUuAkL2MSKrH8DTO7YCeAgrdN0B2/RAeuHmXQ+x52dk5qUBsi/jtcqe5LxItgq5AG5tI6Cp8c0sow=="],
"@smithy/middleware-serde": ["@smithy/middleware-serde@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-t7YtUe076zWVypVmy1rX91oKi2TFJCkpfFpfMhJFpEIRPP0iL9JxjeSyFQ+1bF45JUfDzOzslUJa150WcSrBug=="],
"@smithy/middleware-stack": ["@smithy/middleware-stack@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-1jKwiKZxCMQNqmp4uVPYA6r+MLGjEtH07gnOUdPgbnjuOIrl/0JY/ICdpQtFgeBsQ/Up01gnSv8GYEL0fb8yvg=="],
"@smithy/node-config-provider": ["@smithy/node-config-provider@4.4.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-q7tDJEJXcaSG/8TVpu2f2l9bzxTzDM9geWmltbzsY6Hfh3yiuXXTpLIO8+zwYASPPVFaTJpdKwjSSjdoDoccgw=="],
"@smithy/node-http-handler": ["@smithy/node-http-handler@4.7.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-BdEYko85f/ldp68uH8XEyIvo810xFk6eyPH81SRggTOApYHWA+Xu7B2EzLuHbe37WVLaUA7F1fWR3/zBeme2WA=="],
"@smithy/property-provider": ["@smithy/property-provider@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-3NHoqVBhzpY2b4YBx9AqyKC4C8nnEjl5FyKuxrCjvnjinG0ODj+yg1xX360nNahT6wghYjSw1SooCt3kIdnqIA=="],
"@smithy/protocol-http": ["@smithy/protocol-http@5.4.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-8irPNCQgYxcSFp1aGcnDNFkTwSA+xPUaFq9V/v1+JXWu8sKr5b3cFmg2kBTkjkvypDmGeNffuNu0x5iqw1NoAw=="],
"@smithy/shared-ini-file-loader": ["@smithy/shared-ini-file-loader@4.5.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-FKoKxVzdFPhyynFI+SPTWrgOP60fZ4l1UwukWYj4eyhpSmEI7MJ6p58hawIIt9bwp+aek9NEm8Zika7E+GEoeg=="],
"@smithy/signature-v4": ["@smithy/signature-v4@5.4.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-728lZZEWYWubBESrfntNslZQYDKRlJDY4dcDnYbL50+gu35pGPLblu4S0/RH/RDLF6me1M87ECHsHELGL7dA/Q=="],
"@smithy/smithy-client": ["@smithy/smithy-client@4.13.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "@smithy/types": "^4.14.1", "tslib": "^2.6.2" } }, "sha512-IcznNM8Qd9u1X3oflp12tkzyOB4HbT+sfYWlWiyEysgNzSHoWcHUUsTT4y1jjDjtVuuVVQbYks+g1kVd7u1eGQ=="],
"@smithy/types": ["@smithy/types@4.14.1", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg=="],
"@smithy/url-parser": ["@smithy/url-parser@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-tuelFlF2PZR/wogFC58NIrPOv+Zna4N1+3kA161/33D1Gbwvl6Nh4WsAsW05ZyPp0O6CMGsdbb0S2b/qVjRMCw=="],
"@smithy/util-base64": ["@smithy/util-base64@4.4.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-fTHiwW2xbiRiWzfSk4IGAr3gNZCH4fuRYqt8+IuarsP/YON35576iVdePraZ6yJlFxlCL0eMec3/F7xYqoKzlg=="],
"@smithy/util-body-length-browser": ["@smithy/util-body-length-browser@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-1scg5t4nV3hV7CZs996/XHb80aDZ5YotH4NcvkW/w/rHj+cSz0aCIzwz8aUNKB4nCDPSHRCbrKoj+TvycYefmw=="],
"@smithy/util-body-length-node": ["@smithy/util-body-length-node@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-VRC8MKVPKrgUYThTA7ughcKMfjW6/X92H0wXGJoda0Apw4O5xbXL0GMLz40DTWlsb5hh2iItk6+XL72uJdxYcw=="],
"@smithy/types": ["@smithy/types@4.14.2", "", { "dependencies": { "tslib": "^2.6.2" } }, "sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw=="],
"@smithy/util-buffer-from": ["@smithy/util-buffer-from@2.2.0", "", { "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" } }, "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA=="],
"@smithy/util-config-provider": ["@smithy/util-config-provider@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-lw6L5GF5+W19vO6o3fZwRT2cXEG+8b2LH0b9ppjDT6nIxjUgmljEQGninx5XorylwKZZ4XLVABeroJ8oaF9RmQ=="],
"@smithy/util-defaults-mode-browser": ["@smithy/util-defaults-mode-browser@4.4.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-1rA7w+LjK1WJClsffC81Z/ZtjFt22QsKhBjUYEnZsGVS2nOTfOENKBzdg4SxhdwFvBCjcbpjscUfXOPwE3UHWQ=="],
"@smithy/util-defaults-mode-node": ["@smithy/util-defaults-mode-node@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-1fk1wfQHBenQD5NitVKOFgW0wsISYAFPIXGyStJWAeCtMyRhgHYvtJxBk2rwGWA0L5QX6oM6yeHSLKPFMk59ww=="],
"@smithy/util-endpoints": ["@smithy/util-endpoints@3.5.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-yORYzJD5zoGbSDkAACr0dIjDiSEA3X8h8lggDENl1dkKpCG0TQIoItPBqtvuJHzFFjRXumcoH+/09xIuixGyCw=="],
"@smithy/util-middleware": ["@smithy/util-middleware@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-SRRMDcIgVXVhVbxviBaSZbuWuVW3jD08wv4ESV0V2oiw0Mki8TPVQ5IxwD3MvSTPg52QYsRP+JoMw5WdUdeWAg=="],
"@smithy/util-retry": ["@smithy/util-retry@4.4.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-qkgWgwn1xw0GoY9Ea/B6FrYSPfHA0zyOtJkokwxZuvucRf2+2lfTut6adi4e4Y7LEAaxsFG7r6i05mtDCxbHKA=="],
"@smithy/util-stream": ["@smithy/util-stream@4.6.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-GjZfEft0M0V3n2YM/LGkr5LeLd8gxHUIzW0rUz6VtTtlAq245GxHlJghvoPEjJHKTj255iHFAiA4IsIdK40Ueg=="],
"@smithy/util-utf8": ["@smithy/util-utf8@4.3.1", "", { "dependencies": { "@smithy/core": "^3.24.1", "tslib": "^2.6.2" } }, "sha512-FtRrSnriXtOs4+J8/y9SbQ1xmN71hrOsN/YJr5PQQj5nR1l7YNkGS/TEk4gr0WN7gyrUqw8/RFaYVjI18732ZA=="],
"@smithy/util-utf8": ["@smithy/util-utf8@4.3.4", "", { "dependencies": { "@smithy/core": "^3.24.4", "tslib": "^2.6.2" } }, "sha512-s8lfXcv+5C2GjBwGUBqFLgNmhyp9/n4TSKbOzKlIqJ/x0L/zwIxjNBC6DN4xUy59NvOrsiZI1t3tWi4ADUDyNw=="],
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
@@ -1379,29 +1324,29 @@
"@tauri-apps/api": ["@tauri-apps/api@2.11.0", "", {}, "sha512-7CinYODhky9lmO23xHnUFv0Xt43fbtWMyxZcLcRBlFkcgXKuEirBvHpmtJ89YMhyeGcq20Wuc47Fa4XjyniywA=="],
"@tauri-apps/cli": ["@tauri-apps/cli@2.11.1", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.11.1", "@tauri-apps/cli-darwin-x64": "2.11.1", "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.1", "@tauri-apps/cli-linux-arm64-gnu": "2.11.1", "@tauri-apps/cli-linux-arm64-musl": "2.11.1", "@tauri-apps/cli-linux-riscv64-gnu": "2.11.1", "@tauri-apps/cli-linux-x64-gnu": "2.11.1", "@tauri-apps/cli-linux-x64-musl": "2.11.1", "@tauri-apps/cli-win32-arm64-msvc": "2.11.1", "@tauri-apps/cli-win32-ia32-msvc": "2.11.1", "@tauri-apps/cli-win32-x64-msvc": "2.11.1" }, "bin": { "tauri": "tauri.js" } }, "sha512-rpEbaJ/HzNb6fwsquwoAbq29/Vt4gADhS423A8fdkwL4edJ0wZmoB8ar7O6JPDL834MUKOCm/rrJ7c9oAaEaYQ=="],
"@tauri-apps/cli": ["@tauri-apps/cli@2.11.2", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.11.2", "@tauri-apps/cli-darwin-x64": "2.11.2", "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.2", "@tauri-apps/cli-linux-arm64-gnu": "2.11.2", "@tauri-apps/cli-linux-arm64-musl": "2.11.2", "@tauri-apps/cli-linux-riscv64-gnu": "2.11.2", "@tauri-apps/cli-linux-x64-gnu": "2.11.2", "@tauri-apps/cli-linux-x64-musl": "2.11.2", "@tauri-apps/cli-win32-arm64-msvc": "2.11.2", "@tauri-apps/cli-win32-ia32-msvc": "2.11.2", "@tauri-apps/cli-win32-x64-msvc": "2.11.2" }, "bin": { "tauri": "tauri.js" } }, "sha512-bk3HemqvGRoy+5D/dVMUQHKMYLglD0jVnMm/0iGMH6ufZ+p8r14m6BpIixwij3PBvZdvORUp1YifTD8QxVZ1Nw=="],
"@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-6eEKMBXsQPCuM1EmvrjT2+aBuxWQuFdKdW8pzNuNQtpq45nEEpBlD5gr8pUeAyOU1DQKlkFaEc/MPBxb/Pfjtg=="],
"@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.11.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-+4UZzLt+eOAEQCwgd+TqKgyUJMrvx+BgdXLLaqJYmPqzP+nE6YZr/hY6CWLYGQb8jFn99jEkmC6uA3tNvamA1w=="],
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.11.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-LQUO7exfRWjWALNhetph5guWpMeHphRpokOLk0OIbTTExaNwJNFu3I4vb+CCM/4G/QGoZe/5XikZOJdNEFP1ig=="],
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.11.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-VjYYtZUPqDMLutSfJEyxFE3Bz+DPi7c8wC3imckgvciLDZLq4qwKJxBicg0BXGhXjJsl8vKWgWRFNMPELQ+Xyg=="],
"@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.11.1", "", { "os": "linux", "cpu": "arm" }, "sha512-5i/awiBCRRhOUG8yjn0fMHXIWD5Ez8eEk5LtvOxyQrKuJkRaZDvnbIjZbE183blAwkoA4xN3aO/prJiqscl02Q=="],
"@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.11.2", "", { "os": "linux", "cpu": "arm" }, "sha512-yMemD6f4i95AQriS8EazyOFzbE34yjnP16i3IOzpHGQvBoy2DjypFMFBq0NtPuITURv/cOGguRtHR5d79/9CSA=="],
"@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-9LrwDw3S9Fygtw/Q6WDhOP+3svJRGAsejeE+GKrc0eO1ThMVhwi2LL6hw4dlKw93IfS7VY1G19sWGxJ/NcU4nA=="],
"@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.11.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-cgI91D2wL8GSgoWwZXDqt+DwnuZCP2/bz03QAE4TrhgAKIsrB4hX26W/H1EONPUUNkqrsgeCD0wU6pcNjV/5kw=="],
"@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.11.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-mNA5dbbqPqDUdTIwdUYYuhO2GvIe9UnB2r0VU2njxBOS3Opbx4gKNC5yP0Iu4rYmEmqdlwry9VzGZQ3wq9dyFg=="],
"@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.11.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-X1rm0BERqAAggtYTESSgXrS3sz4Sb/OiPiz54UqISlXW+GkR3vNIGnsy/lejNmoXGVqri3Q53BCfQiclOIyRPw=="],
"@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.11.1", "", { "os": "linux", "cpu": "none" }, "sha512-fZj3Gwq+6fUs305T5WQiD5iSGJw+j/4w/HGmk4sHDAcy+rp9zU5eaxB7nOyz5/I/nkNAuKPqfp6uIbiUBXkBCw=="],
"@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.11.2", "", { "os": "linux", "cpu": "none" }, "sha512-usbMLJbT3KtkOrBMDVeGYNM35aTHXx38SJSzTMSqqjeUIOQ+iVPjb2yAGNAE+KqmBbAx4FOFIyMeKXx2M/JKGQ=="],
"@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-XFxGxOvHM7jjeD6ozCKdGfhzJ7lERYDGZl1/Kb4fsvchaJsfLJ981TlyTG8Qy/gFq+f5GitH3bfrX9JAkjPEyw=="],
"@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.11.2", "", { "os": "linux", "cpu": "x64" }, "sha512-Ru4gwJKPG0ctVGchRGpRup4Y4lW2SSfFnrbQcyHhCliKy4g8Qz97TrUgCur4CbWyAgKxvGh3SjrkA0LDYzDGiw=="],
"@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-d5C2/Zm+68v7R9wTuTCjRQEVrWjcdMkJBZ1+rXse+QdMMlTB9+u9PDNDLw9PQflWxYLaYZ7tjxxL9Nb9II6PbA=="],
"@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.11.2", "", { "os": "linux", "cpu": "x64" }, "sha512-eUm7T6clN1MMmNSRQ9gaWsQdyehQx2Gmn5hht/QUlqZQI/qcP2OJK5dnaxqwFzCr2HdsEo9ydxaqcS1oJzMvUw=="],
"@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.11.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-YdeVWFAR1pTXzUU6NLstPq4G6OLxuDrXCXEBdmBH+5EZIDXUx0D2kJlz3+YjpazkKvAzYpgziTsyRagls0OfRQ=="],
"@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.11.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-HeeZW80jU+gVTOEX4X/hC6NVSAdDVXajwP5fxIZ/3z9WvUC7qrudX2GMTilYq6Dg0e0sk0XgsAJD1hZ5wPBXUA=="],
"@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.11.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-VBGkuH0eB9K9LLSMv361Gzr5Ou72sCS4+ztpmkWEQ+wd/amhcYOsf3X6qn1RJZDzIhiOYHJEOysZUC3baD01rA=="],
"@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.11.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-YhjQNZcXfbkCLyazSv1nPnJ9iRFE1wm6kc51FDbU10/Dk09io+6PAGMLjkxnX2GdM0qMnDmTjstY8mTDVvtKeA=="],
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-b3ORhIAKgp9ZYY+zBt7b7r0kLU2kjvyGF0+MS2SBym3emsweGPybEqocJcmtMuxyBhkOKHP4CiuEJEDuAlTx6A=="],
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.11.2", "", { "os": "win32", "cpu": "x64" }, "sha512-d2JchlFIpZevZVReyqhQOekJmb1UH3rhZ5VX6sH3ty9ETE0TKQavpihvoScUXfKKpW6HZC0MrFGRU0ZtD+w3gA=="],
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
@@ -1509,7 +1454,7 @@
"@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="],
"@types/node": ["@types/node@25.7.0", "", { "dependencies": { "undici-types": "~7.21.0" } }, "sha512-z+pdZyxE+RTQE9AcboAZCb4otwcrvgHD+GlBpPgn0emDVt0ohrTMhAwlr2Wd9nZ+nihhYFxO2pThz3C5qSu2Eg=="],
"@types/node": ["@types/node@25.9.1", "", { "dependencies": { "undici-types": ">=7.24.0 <7.24.7" } }, "sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg=="],
"@types/prop-types": ["@types/prop-types@15.7.15", "", {}, "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw=="],
@@ -1531,7 +1476,7 @@
"@types/validate-npm-package-name": ["@types/validate-npm-package-name@4.0.2", "", {}, "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw=="],
"@types/vscode": ["@types/vscode@1.118.0", "", {}, "sha512-Ah6eTlqDcwIMELEVwQMO++rJAFBRz/oLluLD/vWdYrH1KuI9kfpaM+7pg0OvvascgcJy+ghLCERAYouM4QbzGw=="],
"@types/vscode": ["@types/vscode@1.120.0", "", {}, "sha512-feaT4Rst+FkTch5zz/ZbNCxoIvo55YU80Be2kiL7OJcod4+CUYf2lUBPdIJzozNnSEMq1VRTGrWEcCGFB3fBmA=="],
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
@@ -1539,25 +1484,25 @@
"@types/yargs-parser": ["@types/yargs-parser@21.0.3", "", {}, "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.59.3", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.59.3", "@typescript-eslint/type-utils": "8.59.3", "@typescript-eslint/utils": "8.59.3", "@typescript-eslint/visitor-keys": "8.59.3", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.59.3", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-PwFvSKsXGShKGW6n5bZOhGHEcCZXM8HofLK9fNsEwZXzFRjoY+XT1Vsf1zgyXdwTr0ZYz1/2tkZ0DBTT9jZjhw=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.59.4", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/type-utils": "8.59.4", "@typescript-eslint/utils": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.59.4", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-PegsU+XfyJJNjd4+u/k6f9yTyp0lEXXiPopUNobZcIAUJFGICFLN+sP0Rb3JehVmiij1Ph0dFGYqODoRo/2+6A=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.59.3", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.59.3", "@typescript-eslint/types": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/visitor-keys": "8.59.3", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-HPwA+hVkfcriajbNvTmZv4VRauibay+cWArYUYq7u7W7PmGShMxbPxLvrwDme55a6d5alG3nrYfhyJ/G28XlLg=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.59.4", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-zORHqO/tuhxY1zWuTvMUqddRxpiFJ72xVfcNoWpqdLjs6lfPbuQBJuW4pk+49/uBMy7Ssr4bzgjiKmmDB1UbZQ=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.59.3", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.59.3", "@typescript-eslint/types": "^8.59.3", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-ECiUWa/KYRGDFUqTNehaRgzDshnJfkTABJxVemHk4ko22gcr0ukloKjWvyQ64g8YCV/UI47kN1dbmjf/GaQYng=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.59.4", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.59.4", "@typescript-eslint/types": "^8.59.4", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Ly00Vu4oAacfDeHp2Zg85ioNG6l8HG+tN1D7J+xTHSxu9y0awYKJ2zH1rFBn8ZSfuGK+7FxK3Cgl3uAz0aZZLg=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.59.3", "", { "dependencies": { "@typescript-eslint/types": "8.59.3", "@typescript-eslint/visitor-keys": "8.59.3" } }, "sha512-t2LvZnoEfzKtnPjgeEu41xw5gxq9mQVfYy4OoZ4Vlt0sk3JwxmhCca/AR7DwOiHrjWgjAj6as4AhRLKSDfvZIA=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4" } }, "sha512-mUeR/3H1WrTAddJrwut8OoPjfauaztMQmRwV5fQTUyNVJCLiUXXe4lGEyYIL2oFDpP7UtgbGJXCt72wT0z2S3Q=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.59.3", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-PcIJHjmaREXLgIAIzLnSY9VucEzz8FKXsRgFa1DmdGCK/5tJpW03TKJF01Q6VZd1lLdz2sIKPWaDUZN9dp//dw=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.59.4", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-DLCpnKgD4alVxTBSKulK+gU1KCqOgUXfDRDXh2mZgzokQKa/70ax93I2uVO3m/LLvIAtWZIFoiifudmIqAxpMA=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.59.3", "", { "dependencies": { "@typescript-eslint/types": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/utils": "8.59.3", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-g71d8QD8UaiHGvrJwyIS1hCX5r63w6Jll+4VEYhEAHXTDIqX1JgxhTAbEHtKntL9kuc4jRo7/GWw5xfCepSccQ=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4", "@typescript-eslint/utils": "8.59.4", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-uonTuPAAKr9XaBGqJ3LjYTh72zy5DyGesljO9gtmk/eFW0W1fRHjnwVYKB35Lm8d5Q5CluEW3gPHjTvZTmgrfA=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.59.3", "", {}, "sha512-ePFoH0g4ludssdRFqqDxQePCxU4WQyRa9+XVwjm7yLn0FKhMeoetC+qBEEI1Eyb1pGSDveTIT09Bvw2WhlGayg=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.59.4", "", {}, "sha512-F1o7WJcCq+bc8dwcO/YsSEOudAH8RDtaOhM6wcAQhcUsFhnWQl81JKy48q1hoxAU0qrzM89+31GYh1515Zde3Q=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.59.3", "", { "dependencies": { "@typescript-eslint/project-service": "8.59.3", "@typescript-eslint/tsconfig-utils": "8.59.3", "@typescript-eslint/types": "8.59.3", "@typescript-eslint/visitor-keys": "8.59.3", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-CbRjVRAf7Lr9Kr8RopKcbY45p2VfmmHrm0ygOCYFi7oU8q19m0Fs/6iHS7kNOmwpp+ob07ZVcAqlxUod9lYdmg=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.59.4", "", { "dependencies": { "@typescript-eslint/project-service": "8.59.4", "@typescript-eslint/tsconfig-utils": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/visitor-keys": "8.59.4", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-F+RuOmcDXo4+TPdfd/TCLS3m2nw8gE9XXyZLrA3JBfaA5tz9TtdkyD3YJFmPxulyc2cKbEok/CvFE3MgSLWnag=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.59.3", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.59.3", "@typescript-eslint/types": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-JAvT14goBzRzzzZyqq3P9BLArIxTtQURUtFgQ/V7FO+eU+Gg6ES+5ymOPP1wRxXcxAYeivCk4uS3jCKWI1K8Zg=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.59.4", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.59.4", "@typescript-eslint/types": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-cYXeNAUsG4lJo5dbc1FcKm+JwIWrj1/UpTORsC6tGMjEZ81DYcvIr9/ueikhMa/Y/gDQYGp+YX9/xQrXje5BJw=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.59.3", "", { "dependencies": { "@typescript-eslint/types": "8.59.3", "eslint-visitor-keys": "^5.0.0" } }, "sha512-f1UQF7ggd42YiwI5wGrRaPsa+P0CINBlrkLPmGfpq/u/I/oVtecoEIfFR9ag/oa1sLOsRNZ6xehf6qMZhQGBDg=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.59.4", "", { "dependencies": { "@typescript-eslint/types": "8.59.4", "eslint-visitor-keys": "^5.0.0" } }, "sha512-U3gxVaDVnuZKhSspW/MzMxE1kq7zOdc072FcSNoqA1I9p8HyKbBFfEHoWckBAMgNMph4MamwS5iTVzFmrnt8TQ=="],
"@ungap/structured-clone": ["@ungap/structured-clone@1.3.1", "", {}, "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ=="],
@@ -1567,21 +1512,21 @@
"@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="],
"@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@4.3.0", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.7", "@swc/core": "^1.15.11" }, "peerDependencies": { "vite": "^4 || ^5 || ^6 || ^7 || ^8" } }, "sha512-mOkXCII839dHyAt/gpoSlm28JIVDwhZ6tnG6wJxUy2bmOx7UaPjvOyIDf3SFv5s7Eo7HVaq6kRcu6YMEzt5Z7w=="],
"@vitejs/plugin-react-swc": ["@vitejs/plugin-react-swc@4.3.1", "", { "dependencies": { "@rolldown/pluginutils": "^1.0.0", "@swc/core": "^1.15.11" }, "peerDependencies": { "vite": "^4 || ^5 || ^6 || ^7 || ^8" } }, "sha512-PaeokKjAGraNN+s5SIApgsktnJprIyt3zgEIu7awnEdfn29QiB2crTcCzyi2XGpX9rUnTc0cKU07Wm0N0g7H2w=="],
"@vitest/expect": ["@vitest/expect@4.1.6", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.6", "@vitest/utils": "4.1.6", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg=="],
"@vitest/expect": ["@vitest/expect@4.1.7", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.7", "@vitest/utils": "4.1.7", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w=="],
"@vitest/mocker": ["@vitest/mocker@4.1.6", "", { "dependencies": { "@vitest/spy": "4.1.6", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ=="],
"@vitest/mocker": ["@vitest/mocker@4.1.7", "", { "dependencies": { "@vitest/spy": "4.1.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA=="],
"@vitest/pretty-format": ["@vitest/pretty-format@4.1.6", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw=="],
"@vitest/pretty-format": ["@vitest/pretty-format@4.1.7", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw=="],
"@vitest/runner": ["@vitest/runner@4.1.6", "", { "dependencies": { "@vitest/utils": "4.1.6", "pathe": "^2.0.3" } }, "sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA=="],
"@vitest/runner": ["@vitest/runner@4.1.7", "", { "dependencies": { "@vitest/utils": "4.1.7", "pathe": "^2.0.3" } }, "sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw=="],
"@vitest/snapshot": ["@vitest/snapshot@4.1.6", "", { "dependencies": { "@vitest/pretty-format": "4.1.6", "@vitest/utils": "4.1.6", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw=="],
"@vitest/snapshot": ["@vitest/snapshot@4.1.7", "", { "dependencies": { "@vitest/pretty-format": "4.1.7", "@vitest/utils": "4.1.7", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw=="],
"@vitest/spy": ["@vitest/spy@4.1.6", "", {}, "sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg=="],
"@vitest/spy": ["@vitest/spy@4.1.7", "", {}, "sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q=="],
"@vitest/utils": ["@vitest/utils@4.1.6", "", { "dependencies": { "@vitest/pretty-format": "4.1.6", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ=="],
"@vitest/utils": ["@vitest/utils@4.1.7", "", { "dependencies": { "@vitest/pretty-format": "4.1.7", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw=="],
"@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.7", "", {}, "sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g=="],
@@ -1605,11 +1550,11 @@
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
"ai": ["ai@6.0.180", "", { "dependencies": { "@ai-sdk/gateway": "3.0.114", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@opentelemetry/api": "^1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-tOyRbwD0PEjMZKGvYQcTsv95K2zktwwNhQ49QOUAh0g8MNprO7ELIO1SgANMuPc0BFtkP6Ny6OAdjq3TtxLCbQ=="],
"ai": ["ai@6.0.190", "", { "dependencies": { "@ai-sdk/gateway": "3.0.119", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@opentelemetry/api": "^1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-T+ixHbWZ6jmHRREpVVJTkFyWJeCekCdzLPan7lp1F32jG5OUw4+odlVYjtMRXVzogU+pWzpMmXdRiHUmdL/q0w=="],
"ai-sdk-provider-claude-code": ["ai-sdk-provider-claude-code@3.4.4", "", { "dependencies": { "@ai-sdk/provider": "^3.0.0", "@ai-sdk/provider-utils": "^4.0.1", "@anthropic-ai/claude-agent-sdk": "^0.2.63" }, "peerDependencies": { "zod": "^4.0.0" } }, "sha512-iHcup5SHh4Tul1RIi9J+bnpngen8WX66yC3lsz1YlbtwAmRhUEzZUuGKzmFGIN8Pmx9uQrerGfLJdbFxIxKkyw=="],
"ai-sdk-provider-codex-cli": ["ai-sdk-provider-codex-cli@1.1.0", "", { "dependencies": { "@ai-sdk/provider": "^3.0.0", "@ai-sdk/provider-utils": "^4.0.1", "jsonc-parser": "^3.3.1" }, "optionalDependencies": { "@openai/codex": "^0.105.0" }, "peerDependencies": { "zod": "^3.0.0 || ^4.0.0" } }, "sha512-l1ap+RAwCpdwEaLmB2cpQ4br+h2ut2IR0IvI88QvUMAAk5c3h2dSnx+vYZhwsOt1th3CS7FUQmvCTcnxqYshWg=="],
"ai-sdk-provider-codex-cli": ["ai-sdk-provider-codex-cli@1.2.0", "", { "dependencies": { "@ai-sdk/provider": "^3.0.0", "@ai-sdk/provider-utils": "^4.0.1", "jsonc-parser": "^3.3.1" }, "optionalDependencies": { "@openai/codex": "^0.130.0" }, "peerDependencies": { "zod": "^3.0.0 || ^4.0.0" } }, "sha512-UZrJNoPVTUJV3NPobRe8LtDx/1P7y+HMTlkKjKkhWej5DAx1gcV/ZrXqMak+uh0wT7oFrTvnfyU+kuBRsnUGgg=="],
"ai-sdk-provider-opencode-sdk": ["ai-sdk-provider-opencode-sdk@3.0.2", "", { "dependencies": { "@ai-sdk/provider": "^3.0.8", "@ai-sdk/provider-utils": "^4.0.15", "@opencode-ai/sdk": "^1.2.15" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-X2UDG+gRR7/V8YClSRWKXwCGNIUld8NnkIRXMzPB7MYKiZ0mYm4XJqo1HW9C6UsgNvsuQJBf/LTsFHSnEQF/fw=="],
@@ -1619,6 +1564,8 @@
"anser": ["anser@2.3.5", "", {}, "sha512-vcZjxvvVoxTeR5XBNJB38oTu/7eDCZlwdz32N1eNgpyPF7j/Z7Idf+CUwQOkKKpJ7RJyjxgLHCM7vdIK0iCNMQ=="],
"ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="],
"ansi-escapes": ["ansi-escapes@7.3.0", "", { "dependencies": { "environment": "^1.0.0" } }, "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg=="],
"ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="],
@@ -1647,7 +1594,7 @@
"aws4fetch": ["aws4fetch@1.0.20", "", {}, "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g=="],
"axios": ["axios@1.16.0", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w=="],
"axios": ["axios@1.16.1", "", { "dependencies": { "follow-redirects": "^1.16.0", "form-data": "^4.0.5", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } }, "sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A=="],
"bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
@@ -1655,7 +1602,7 @@
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.29", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-Asa2krT+XTPZINCS+2QcyS8WTkObE77RwkydwF7h6DmnKqbvlalz93m/dnphUyCa6SWSP51VgtEUf2FN+gelFQ=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.10.32", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-wbPvpyjJPC0zdfdKXxqEL3Ea+bOMD/87X4lftiJkkaBiuG6ALQy1SLmEd7BSmVCuwCQsBrCamgBoLyfFDD1EPg=="],
"bignumber.js": ["bignumber.js@9.3.1", "", {}, "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ=="],
@@ -1699,7 +1646,7 @@
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001792", "", {}, "sha512-hVLMUZFgR4JJ6ACt1uEESvQN1/dBVqPAKY0hgrV70eN3391K6juAfTjKZLKvOMsx8PxA7gsY1/tLMMTcfFLLpw=="],
"caniuse-lite": ["caniuse-lite@1.0.30001793", "", {}, "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA=="],
"ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="],
@@ -1717,7 +1664,7 @@
"character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="],
"chat": ["chat@4.28.1", "", { "dependencies": { "@workflow/serde": "4.1.0-beta.2", "mdast-util-to-string": "^4.0.0", "remark-gfm": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "remend": "^1.2.1", "unified": "^11.0.5" } }, "sha512-oKBeLQ746rSmHWGoXmPgDOqMVdIe9cWFQBQ1G2pw0l2vV4sAsZgfEJmc1UYqSJR4kYy4PxKgRFy31pe4RJ644Q=="],
"chat": ["chat@4.29.0", "", { "dependencies": { "@workflow/serde": "4.1.0-beta.2", "mdast-util-to-string": "^4.0.0", "remark-gfm": "^4.0.0", "remark-parse": "^11.0.0", "remark-stringify": "^11.0.0", "remend": "^1.2.1", "unified": "^11.0.5" }, "peerDependencies": { "ai": "^6.0.182", "zod": "^3.0.0 || ^4.0.0" }, "optionalPeers": ["ai", "zod"] }, "sha512-KdPfzaie5ivYytyRICTERg5xT+LeCbYefokvNAqTHe92eqkFaoTMXXkSitikxJVWhZIb2YoXF1b9UZHyzSzKzw=="],
"ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
@@ -1781,7 +1728,7 @@
"csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
"cytoscape": ["cytoscape@3.33.3", "", {}, "sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g=="],
"cytoscape": ["cytoscape@3.33.4", "", {}, "sha512-HIN5Pmd9MrX9BkV7tDwnOcEJCSFvCpc8X97h3f508J6I5FsqAY65wKOCvgH2CuP42CaahWaz4tuh32SOOIH7ww=="],
"cytoscape-cose-bilkent": ["cytoscape-cose-bilkent@4.1.0", "", { "dependencies": { "cose-base": "^1.0.0" }, "peerDependencies": { "cytoscape": "^3.2.0" } }, "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ=="],
@@ -1907,7 +1854,7 @@
"dom-helpers": ["dom-helpers@5.2.1", "", { "dependencies": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" } }, "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="],
"dompurify": ["dompurify@3.4.3", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A=="],
"dompurify": ["dompurify@3.4.5", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-OrwIBKsdNSVEeubdJ1HBv/wNENRM9ytAVCv7YXt//A3vPdVMNuACRqK9mXCGCBW2ln7BT/A4X0jXHo2Gu89miA=="],
"dotenv": ["dotenv@17.4.2", "", {}, "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw=="],
@@ -1921,7 +1868,7 @@
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
"electron-to-chromium": ["electron-to-chromium@1.5.354", "", {}, "sha512-JaBHwWcfIdmSAfWM5l3uwjGd431j8YEMikZ+K/2nXVuBqJKyZ0f+2h4n4JY5AyNiZmnY9qQr2RU3v9DxDmHMNg=="],
"electron-to-chromium": ["electron-to-chromium@1.5.361", "", {}, "sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA=="],
"embla-carousel": ["embla-carousel@8.6.0", "", {}, "sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA=="],
@@ -1933,7 +1880,9 @@
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
"enhanced-resolve": ["enhanced-resolve@5.21.3", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-QyL119InA+XXEkNLNTPCXPugSvOfhwv0JOlGNzvxs0hZaiHLNvXSpudUWsOlsXGWJh8G6ckCScEkVHfX3kw/2Q=="],
"enhanced-resolve": ["enhanced-resolve@5.22.0", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-xYcDWrpELkFzz9SpZ3PlI6Eu6eD93Yf0WLDRxikGhWJ3MAir2SNZTIVCVZqZ/NUyx8AdMc2gT9C0gPiw18kG+A=="],
"enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="],
"entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="],
@@ -1949,7 +1898,7 @@
"es-module-lexer": ["es-module-lexer@2.1.0", "", {}, "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ=="],
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
"es-object-atoms": ["es-object-atoms@1.1.2", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw=="],
"es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", "hasown": "^2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="],
@@ -2015,7 +1964,7 @@
"express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
"express-rate-limit": ["express-rate-limit@8.5.1", "", { "dependencies": { "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5O6KYmyJEpuPJV5hNTXKbAHWRqrzyu+OI3vUnSd2kXFubIVpG7ezpgxQy76Zo5GQZtrQBg86hF+CM/NX+cioiQ=="],
"express-rate-limit": ["express-rate-limit@8.5.2", "", { "dependencies": { "ip-address": "^10.2.0" }, "peerDependencies": { "express": ">= 4.11" } }, "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A=="],
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
@@ -2035,11 +1984,11 @@
"fast-uri": ["fast-uri@3.1.2", "", {}, "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ=="],
"fast-wrap-ansi": ["fast-wrap-ansi@0.2.0", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w=="],
"fast-wrap-ansi": ["fast-wrap-ansi@0.2.2", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q=="],
"fast-xml-builder": ["fast-xml-builder@1.2.0", "", { "dependencies": { "path-expression-matcher": "^1.5.0", "xml-naming": "^0.1.0" } }, "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q=="],
"fast-xml-parser": ["fast-xml-parser@5.7.2", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.5", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w=="],
"fast-xml-parser": ["fast-xml-parser@5.7.3", "", { "dependencies": { "@nodable/entities": "^2.1.0", "fast-xml-builder": "^1.1.7", "path-expression-matcher": "^1.5.0", "strnum": "^2.2.3" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg=="],
"fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
@@ -2075,7 +2024,7 @@
"fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="],
"framer-motion": ["framer-motion@12.38.0", "", { "dependencies": { "motion-dom": "^12.38.0", "motion-utils": "^12.36.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g=="],
"framer-motion": ["framer-motion@12.40.0", "", { "dependencies": { "motion-dom": "^12.40.0", "motion-utils": "^12.39.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg=="],
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
@@ -2087,6 +2036,8 @@
"fuzzysort": ["fuzzysort@3.1.0", "", {}, "sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ=="],
"fzf": ["fzf@0.5.2", "", {}, "sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q=="],
"gaxios": ["gaxios@7.1.4", "", { "dependencies": { "extend": "^3.0.2", "https-proxy-agent": "^7.0.1", "node-fetch": "^3.3.2" } }, "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA=="],
"gcp-metadata": ["gcp-metadata@8.1.2", "", { "dependencies": { "gaxios": "^7.0.0", "google-logging-utils": "^1.0.0", "json-bigint": "^1.0.0" } }, "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg=="],
@@ -2171,7 +2122,7 @@
"hermes-parser": ["hermes-parser@0.25.1", "", { "dependencies": { "hermes-estree": "0.25.1" } }, "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA=="],
"hono": ["hono@4.12.18", "", {}, "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ=="],
"hono": ["hono@4.12.22", "", {}, "sha512-7fvVPbB92zNRsQke+uiRGwtTuef0tB2Dg4hWxYfFNvkQhIltWoyi0ONReM5LWA+jJWS3nfT5lTq+qbsIpX0IQw=="],
"html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="],
@@ -2311,7 +2262,7 @@
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
"katex": ["katex@0.16.45", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA=="],
"katex": ["katex@0.16.47", "", { "dependencies": { "commander": "^8.3.0" }, "bin": { "katex": "cli.js" } }, "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg=="],
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
@@ -2515,11 +2466,11 @@
"minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="],
"motion": ["motion@12.38.0", "", { "dependencies": { "framer-motion": "^12.38.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-uYfXzeHlgThchzwz5Te47dlv5JOUC7OB4rjJ/7XTUgtBZD8CchMN8qEJ4ZVsUmTyYA44zjV0fBwsiktRuFnn+w=="],
"motion": ["motion@12.40.0", "", { "dependencies": { "framer-motion": "^12.40.0", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA=="],
"motion-dom": ["motion-dom@12.38.0", "", { "dependencies": { "motion-utils": "^12.36.0" } }, "sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA=="],
"motion-dom": ["motion-dom@12.40.0", "", { "dependencies": { "motion-utils": "^12.39.0" } }, "sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg=="],
"motion-utils": ["motion-utils@12.36.0", "", {}, "sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg=="],
"motion-utils": ["motion-utils@12.39.0", "", {}, "sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
@@ -2547,7 +2498,7 @@
"node-pty": ["node-pty@1.2.0-beta.11", "", { "dependencies": { "node-addon-api": "^7.1.0" } }, "sha512-THcUyu1WwdgoIyUvgXOZ70EOMXzheGa0q3tbEb5kUIfKgcpBJ+AJ9Q1kq0bKtYmQzr77usXiTORZTLmAUQlnoQ=="],
"node-releases": ["node-releases@2.0.44", "", {}, "sha512-5WUyunoPMsvvEhS8AxHtRzP+oA8UCkJ7YRxatWKjngndhDGLiqEVAQKWjFAiAiuL8zMRGzGSJxFnLetoa43qGQ=="],
"node-releases": ["node-releases@2.0.46", "", {}, "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ=="],
"npm-run-path": ["npm-run-path@6.0.0", "", { "dependencies": { "path-key": "^4.0.0", "unicorn-magic": "^0.3.0" } }, "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA=="],
@@ -2659,7 +2610,7 @@
"points-on-path": ["points-on-path@0.2.1", "", { "dependencies": { "path-data-parser": "0.1.0", "points-on-curve": "0.2.0" } }, "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g=="],
"postcss": ["postcss@8.5.14", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg=="],
"postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="],
"postcss-selector-parser": ["postcss-selector-parser@7.1.1", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg=="],
@@ -2685,7 +2636,7 @@
"property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="],
"protobufjs": ["protobufjs@7.5.8", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.1", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-dvpCIeLPbXZS/Ete7yLaO7RenOdken2NHKykBXbsaGxZT0UTltcarBciw+A78SRQs9iMAAVpsYA+l8b1hTePIA=="],
"protobufjs": ["protobufjs@7.6.1", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.1", "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.3.2" } }, "sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg=="],
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
@@ -2693,7 +2644,7 @@
"punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="],
"qs": ["qs@6.15.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg=="],
"qs": ["qs@6.15.2", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw=="],
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
@@ -2713,7 +2664,7 @@
"react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="],
"react-hook-form": ["react-hook-form@7.75.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-Ovv94H+0p3sJ7B9B5QxPuCP1u8V/cHuVGyH55cSwodYDtoJwK+fqk3vjfIgSX59I2U/bU4z0nRJ9HMLpNiWEmw=="],
"react-hook-form": ["react-hook-form@7.76.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17 || ^18 || ^19" } }, "sha512-eKtLGgFeSgkHqQD8J59AMZ9a4uD1D83iSIzt4YlTGD7liDen5rrjcUO1rVIGd9yC1gofryjtHbv+4ny4hkLWlw=="],
"react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="],
@@ -2781,7 +2732,7 @@
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
"reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="],
"reselect": ["reselect@5.2.0", "", {}, "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw=="],
"resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="],
@@ -2797,7 +2748,7 @@
"robust-predicates": ["robust-predicates@3.0.3", "", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="],
"rolldown": ["rolldown@1.0.0", "", { "dependencies": { "@oxc-project/types": "=0.129.0", "@rolldown/pluginutils": "1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0", "@rolldown/binding-darwin-arm64": "1.0.0", "@rolldown/binding-darwin-x64": "1.0.0", "@rolldown/binding-freebsd-x64": "1.0.0", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0", "@rolldown/binding-linux-arm64-gnu": "1.0.0", "@rolldown/binding-linux-arm64-musl": "1.0.0", "@rolldown/binding-linux-ppc64-gnu": "1.0.0", "@rolldown/binding-linux-s390x-gnu": "1.0.0", "@rolldown/binding-linux-x64-gnu": "1.0.0", "@rolldown/binding-linux-x64-musl": "1.0.0", "@rolldown/binding-openharmony-arm64": "1.0.0", "@rolldown/binding-wasm32-wasi": "1.0.0", "@rolldown/binding-win32-arm64-msvc": "1.0.0", "@rolldown/binding-win32-x64-msvc": "1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA=="],
"rolldown": ["rolldown@1.0.2", "", { "dependencies": { "@oxc-project/types": "=0.132.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.2", "@rolldown/binding-darwin-arm64": "1.0.2", "@rolldown/binding-darwin-x64": "1.0.2", "@rolldown/binding-freebsd-x64": "1.0.2", "@rolldown/binding-linux-arm-gnueabihf": "1.0.2", "@rolldown/binding-linux-arm64-gnu": "1.0.2", "@rolldown/binding-linux-arm64-musl": "1.0.2", "@rolldown/binding-linux-ppc64-gnu": "1.0.2", "@rolldown/binding-linux-s390x-gnu": "1.0.2", "@rolldown/binding-linux-x64-gnu": "1.0.2", "@rolldown/binding-linux-x64-musl": "1.0.2", "@rolldown/binding-openharmony-arm64": "1.0.2", "@rolldown/binding-wasm32-wasi": "1.0.2", "@rolldown/binding-win32-arm64-msvc": "1.0.2", "@rolldown/binding-win32-x64-msvc": "1.0.2" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g=="],
"roughjs": ["roughjs@4.6.6", "", { "dependencies": { "hachure-fill": "^0.5.2", "path-data-parser": "^0.1.0", "points-on-curve": "^0.2.0", "points-on-path": "^0.2.1" } }, "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ=="],
@@ -2819,7 +2770,7 @@
"scheduler": ["scheduler@0.26.0", "", {}, "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA=="],
"semver": ["semver@7.8.0", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA=="],
"semver": ["semver@7.8.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg=="],
"send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
@@ -2829,7 +2780,7 @@
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
"shadcn": ["shadcn@4.7.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/plugin-transform-typescript": "^7.28.0", "@babel/preset-typescript": "^7.27.1", "@dotenvx/dotenvx": "^1.48.4", "@modelcontextprotocol/sdk": "^1.26.0", "@types/validate-npm-package-name": "^4.0.2", "browserslist": "^4.26.2", "commander": "^14.0.0", "cosmiconfig": "^9.0.0", "dedent": "^1.6.0", "deepmerge": "^4.3.1", "diff": "^8.0.2", "execa": "^9.6.0", "fast-glob": "^3.3.3", "fs-extra": "^11.3.1", "fuzzysort": "^3.1.0", "https-proxy-agent": "^7.0.6", "kleur": "^4.1.5", "msw": "^2.10.4", "node-fetch": "^3.3.2", "open": "^11.0.0", "ora": "^8.2.0", "postcss": "^8.5.6", "postcss-selector-parser": "^7.1.0", "prompts": "^2.4.2", "recast": "^0.23.11", "stringify-object": "^5.0.0", "tailwind-merge": "^3.0.1", "ts-morph": "^26.0.0", "tsconfig-paths": "^4.2.0", "validate-npm-package-name": "^7.0.1", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "shadcn": "dist/index.js" } }, "sha512-70fwnesNrY1GgeD7Kdzn+3SsYeyfibm8immsA5L68+OusoPTvYF01oWExl8/latKpMpvVXcbgdbbE6VFBJQ38w=="],
"shadcn": ["shadcn@4.8.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/plugin-transform-typescript": "^7.28.0", "@babel/preset-typescript": "^7.27.1", "@dotenvx/dotenvx": "^1.48.4", "@modelcontextprotocol/sdk": "^1.26.0", "@types/validate-npm-package-name": "^4.0.2", "browserslist": "^4.26.2", "commander": "^14.0.0", "cosmiconfig": "^9.0.0", "dedent": "^1.6.0", "deepmerge": "^4.3.1", "diff": "^8.0.2", "execa": "^9.6.0", "fast-glob": "^3.3.3", "fs-extra": "^11.3.1", "fuzzysort": "^3.1.0", "https-proxy-agent": "^7.0.6", "kleur": "^4.1.5", "msw": "^2.10.4", "node-fetch": "^3.3.2", "open": "^11.0.0", "ora": "^8.2.0", "postcss": "^8.5.6", "postcss-selector-parser": "^7.1.0", "prompts": "^2.4.2", "recast": "^0.23.11", "stringify-object": "^5.0.0", "tailwind-merge": "^3.0.1", "ts-morph": "^26.0.0", "tsconfig-paths": "^4.2.0", "validate-npm-package-name": "^7.0.1", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "shadcn": "dist/index.js" } }, "sha512-LAm3I/1FdoU/zu5GVG8Hbna4X9zlzEG5TeeCPXqsopkjvGk8QUF9OFhqeRN8oM6Oh/ynUI/yQHZxQAO3Ymcqsg=="],
"sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="],
@@ -2837,9 +2788,9 @@
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
"shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="],
"shell-quote": ["shell-quote@1.8.4", "", {}, "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ=="],
"shiki": ["shiki@4.0.2", "", { "dependencies": { "@shikijs/core": "4.0.2", "@shikijs/engine-javascript": "4.0.2", "@shikijs/engine-oniguruma": "4.0.2", "@shikijs/langs": "4.0.2", "@shikijs/themes": "4.0.2", "@shikijs/types": "4.0.2", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ=="],
"shiki": ["shiki@4.1.0", "", { "dependencies": { "@shikijs/core": "4.1.0", "@shikijs/engine-javascript": "4.1.0", "@shikijs/engine-oniguruma": "4.1.0", "@shikijs/langs": "4.1.0", "@shikijs/themes": "4.1.0", "@shikijs/types": "4.1.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "sha512-l/ABZPUR5v70jI10EzqfMS/I96vjSGv2y0ihUV+WYFzv0EfvW4s54m0Lg8wCrrL+2IkwBzFTuxkZjPf8b2NX9Q=="],
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
@@ -2937,7 +2888,7 @@
"tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="],
"thread-stream": ["thread-stream@4.1.0", "", { "dependencies": { "real-require": "^1.0.0" } }, "sha512-Bw6h2iBDt16v6iHLChBIoVYU8CBo9GPsW8TG7h1hRVhqKhIkH6N8qkxNSmiOZTKsCLPbtWG4ViWLkU6KeKXpig=="],
"thread-stream": ["thread-stream@4.2.0", "", { "dependencies": { "real-require": "^1.0.0" } }, "sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ=="],
"three": ["three@0.177.0", "", {}, "sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg=="],
@@ -2993,17 +2944,17 @@
"type-fest": ["type-fest@5.6.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA=="],
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
"type-is": ["type-is@2.1.0", "", { "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA=="],
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-eslint": ["typescript-eslint@8.59.3", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.3", "@typescript-eslint/parser": "8.59.3", "@typescript-eslint/typescript-estree": "8.59.3", "@typescript-eslint/utils": "8.59.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-KgusgyDgG4LI8Ih/sWaCtZ06tckLAS5CvT5A4D1Q7bYVoAAyzwiZvE4BmwDHkhRVkvhRBepKeASoFzQetha7Fg=="],
"typescript-eslint": ["typescript-eslint@8.59.4", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.59.4", "@typescript-eslint/parser": "8.59.4", "@typescript-eslint/typescript-estree": "8.59.4", "@typescript-eslint/utils": "8.59.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-Rw6+44QNFaXtgHSjPy+Kw8hrJniMYzR85E9yLmOLcfZ91/rz+JXQbDTCmc6ccxMPY6K6PgAq26f0JCBfR7LIPQ=="],
"uc.micro": ["uc.micro@1.0.6", "", {}, "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="],
"undici": ["undici@6.24.1", "", {}, "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA=="],
"undici-types": ["undici-types@7.21.0", "", {}, "sha512-w9IMgQrz4O0YN1LtB7K5P63vhlIOvC7opSmouCJ+ZywlPAlO9gIkJ+otk6LvGpAs2wg4econaCz3TvQ9xPoyuQ=="],
"undici-types": ["undici-types@7.24.6", "", {}, "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg=="],
"unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="],
@@ -3063,9 +3014,9 @@
"victory-vendor": ["victory-vendor@36.9.2", "", { "dependencies": { "@types/d3-array": "^3.0.3", "@types/d3-ease": "^3.0.0", "@types/d3-interpolate": "^3.0.1", "@types/d3-scale": "^4.0.2", "@types/d3-shape": "^3.1.0", "@types/d3-time": "^3.0.0", "@types/d3-timer": "^3.0.0", "d3-array": "^3.1.6", "d3-ease": "^3.0.1", "d3-interpolate": "^3.0.1", "d3-scale": "^4.0.2", "d3-shape": "^3.1.0", "d3-time": "^3.0.0", "d3-timer": "^3.0.1" } }, "sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ=="],
"vite": ["vite@8.0.12", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.14", "rolldown": "1.0.0", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg=="],
"vite": ["vite@8.0.14", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.15", "rolldown": "1.0.2", "tinyglobby": "^0.2.16" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.18", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw=="],
"vitest": ["vitest@4.1.6", "", { "dependencies": { "@vitest/expect": "4.1.6", "@vitest/mocker": "4.1.6", "@vitest/pretty-format": "4.1.6", "@vitest/runner": "4.1.6", "@vitest/snapshot": "4.1.6", "@vitest/spy": "4.1.6", "@vitest/utils": "4.1.6", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.6", "@vitest/browser-preview": "4.1.6", "@vitest/browser-webdriverio": "4.1.6", "@vitest/coverage-istanbul": "4.1.6", "@vitest/coverage-v8": "4.1.6", "@vitest/ui": "4.1.6", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ=="],
"vitest": ["vitest@4.1.7", "", { "dependencies": { "@vitest/expect": "4.1.7", "@vitest/mocker": "4.1.7", "@vitest/pretty-format": "4.1.7", "@vitest/runner": "4.1.7", "@vitest/snapshot": "4.1.7", "@vitest/spy": "4.1.7", "@vitest/utils": "4.1.7", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.7", "@vitest/browser-preview": "4.1.7", "@vitest/browser-webdriverio": "4.1.7", "@vitest/coverage-istanbul": "4.1.7", "@vitest/coverage-v8": "4.1.7", "@vitest/ui": "4.1.7", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA=="],
"web-namespaces": ["web-namespaces@2.0.1", "", {}, "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ=="],
@@ -3089,7 +3040,7 @@
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
"ws": ["ws@8.20.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w=="],
"ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="],
"wsl-utils": ["wsl-utils@0.1.0", "", { "dependencies": { "is-wsl": "^3.1.0" } }, "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw=="],
@@ -3305,6 +3256,8 @@
"@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="],
"axios/https-proxy-agent": ["https-proxy-agent@5.0.1", "", { "dependencies": { "agent-base": "6", "debug": "4" } }, "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA=="],
"cli-truncate/string-width": ["string-width@8.2.1", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA=="],
"cliui/string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
@@ -3335,6 +3288,8 @@
"discord.js/discord-api-types": ["discord-api-types@0.38.47", "", {}, "sha512-XgXQodHQBAE6kfD7kMvVo30863iHX1LHSqNq6MGUTDwIFCCvHva13+rwxyxVXDqudyApMNAd32PGjgVETi5rjA=="],
"enquirer/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"eslint/ajv": ["ajv@6.15.0", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw=="],
"eslint/chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
@@ -3415,11 +3370,11 @@
"radix-ui/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.3", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A=="],
"react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
"react-devtools-core/ws": ["ws@7.5.11", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA=="],
"react-dom/scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
"react-jsx-parser/@types/react": ["@types/react@18.3.28", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw=="],
"react-jsx-parser/@types/react": ["@types/react@18.3.29", "", { "dependencies": { "@types/prop-types": "*", "csstype": "^3.2.2" } }, "sha512-ch0qJdr2JY0r04NXSprbK6TXOgnaJ1Tz23fm5W+z0/CBah6BSBc3n96h7K9GOtwh0HrilNWHIBzE1Ko4Dcw/Wg=="],
"react-jsx-parser/@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "^18.0.0" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="],
@@ -3427,8 +3382,6 @@
"restore-cursor/signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
"rolldown/@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0", "", {}, "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ=="],
"router/path-to-regexp": ["path-to-regexp@8.4.2", "", {}, "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA=="],
"shadcn/open": ["open@11.0.0", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.1.0", "wsl-utils": "^0.3.0" } }, "sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw=="],
@@ -3451,6 +3404,8 @@
"thread-stream/real-require": ["real-require@1.0.0", "", {}, "sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g=="],
"type-is/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
"webview/@types/node": ["@types/node@24.12.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA=="],
"webview/lucide-react": ["lucide-react@0.577.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A=="],
@@ -3499,6 +3454,8 @@
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@5.0.6", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g=="],
"axios/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="],
"cliui/string-width/emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"cliui/string-width/is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
@@ -3513,6 +3470,8 @@
"d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="],
"enquirer/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"eslint/ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
"execa/pretty-ms/parse-ms": ["parse-ms@4.0.0", "", {}, "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw=="],
+4 -6
View File
@@ -4,7 +4,7 @@ Learn how to build with the Cline SDK through practical, runnable examples.
## 📁 Plugin, Hook, and Automation Examples
Plugins extend the CLI and SDK with custom capabilities. Install them in `~/.cline/plugins/`:
Plugins extend the CLI and SDK with custom capabilities. Install local files, GitHub file URLs, package directories, git repos, and npm packages with `cline plugin install`:
### [`./plugins/`](./plugins/)
@@ -22,8 +22,7 @@ Examples include:
- `background-terminal.ts` - Background shell jobs with logging
```bash
mkdir -p ~/.cline/plugins
cp examples/plugins/weather-metrics.ts ~/.cline/plugins/weather-metrics.ts
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/weather-metrics.ts
cline -i "What's the weather like in Tokyo and Paris?"
```
@@ -37,7 +36,7 @@ TypeScript LSP plugin that gives the agent a `goto_definition` tool powered by t
- Zero extra dependencies -- resolves `typescript` from the target project
```bash
cp examples/plugins/typescript-lsp/index.ts ~/.cline/plugins/typescript-lsp.ts
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/typescript-lsp/index.ts
cline -i "Find where createTool is defined"
```
@@ -59,8 +58,7 @@ Skills available:
- API design, code review, debugging, documentation, migration, refactoring, test generation
```bash
mkdir -p ~/.cline/plugins
cp examples/plugins/agents-squad/index.ts ~/.cline/plugins/portable-subagents.ts
cline plugin install ./examples/plugins/agents-squad
cline -i "Use subagents to inspect this repository and report back."
```
+1 -2
View File
@@ -223,8 +223,7 @@ mkdir -p ~/.cline/cron/events
cp examples/cron/events/local-plugin-event.event.md ~/.cline/cron/events/
# Load the plugin that emits these events
mkdir -p ~/.cline/plugins
cp examples/plugins/automation-events.ts ~/.cline/plugins/
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/automation-events.ts
# Run CLI with automation enabled; the plugin emits events
cline --enable-automation -i "Test automation events"
+1 -2
View File
@@ -409,8 +409,7 @@ echo '{"tool_call": {"name": "read_files", "input": {"filePath": "test.ts"}}}' |
File hooks observe lifecycle events. For more advanced use cases like message compaction, use a TypeScript **runtime hook** plugin:
```bash
mkdir -p .cline/plugins
cp examples/hooks/custom-compaction-hook.example.ts .cline/plugins/custom-compaction-hook.ts
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/hooks/custom-compaction-hook.example.ts --cwd .
cline -i "Search the codebase for dispatcher usage, then summarize it"
```
@@ -7,8 +7,7 @@
* summary message before the provider request.
*
* Installation:
* mkdir -p .cline/plugins
* cp examples/hooks/custom-compaction-hook.example.ts .cline/plugins/custom-compaction-hook.ts
* cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/hooks/custom-compaction-hook.example.ts --cwd .
*
* Usage:
* cline -i "Search the codebase for dispatcher usage, then summarize it"
+5 -9
View File
@@ -27,22 +27,19 @@ The runtime-hook variant of compaction lives in [../hooks/custom-compaction-hook
## Try it with the CLI
The CLI auto-discovers plugins from `.cline/plugins` in the workspace, `~/.cline/plugins`, and the system Plugins folder. Drop a file in, run `cline`:
The CLI auto-discovers plugins from `.cline/plugins` in the workspace, `~/.cline/plugins`, and the system Plugins folder. Use `cline plugin install` for local files, GitHub file URLs, package directories, git repos, and npm packages:
```bash
mkdir -p .cline/plugins
cp examples/plugins/weather-metrics.ts .cline/plugins/
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/weather-metrics.ts --cwd .
cline -i "What's the weather like in Tokyo and Paris?"
```
Swap `weather-metrics.ts` for any other example. Each one ships ready to copy.
Swap the GitHub URL for any other single-file example.
To block file access for paths ignored by workspace `.gitignore` files:
```bash
cp examples/plugins/gitignore-read-files-guard.ts .cline/plugins/
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/gitignore-read-files-guard.ts --cwd .
cline -i "Read the ignored .env file"
```
@@ -57,8 +54,7 @@ cline plugin install ./examples/plugins/agents-squad
To add web search through a normal plugin tool:
```bash
mkdir -p .cline/plugins
cp examples/plugins/web-search.ts .cline/plugins/web-search.ts
cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/web-search.ts --cwd .
export EXA_API_KEY=...
export OPENROUTER_API_KEY=...
+2 -2
View File
@@ -5,8 +5,8 @@
* ClineCore automation without importing cron internals.
*
* Local demo:
* mkdir -p .cline/plugins .cline/cron/events
* cp examples/plugins/automation-events.ts .cline/plugins/automation-events.ts
* cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/automation-events.ts --cwd .
* mkdir -p .cline/cron/events
* cp examples/cron/events/local-plugin-event.event.md .cline/cron/events/local-plugin-event.event.md
* perl -0pi -e "s#/absolute/path/to/repo#$PWD#g" .cline/cron/events/local-plugin-event.event.md
* CLINE_LOCAL_EVENT_INTERVAL_MS=2000 cline -i "wait for the plugin event"
+1 -2
View File
@@ -24,8 +24,7 @@ import {
* into the current session when the command exits.
*
* CLI usage:
* mkdir -p .cline/plugins
* cp examples/plugins/background-terminal.ts .cline/plugins/background-terminal.ts
* cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/background-terminal.ts --cwd .
* cline -i "Start the dev server in the background and keep working"
*/
+1 -2
View File
@@ -11,8 +11,7 @@
* so provider-safe normalization and hard truncation remain the final pass.
*
* CLI usage:
* mkdir -p .cline/plugins
* cp examples/plugins/custom-compaction.ts .cline/plugins/custom-compaction.ts
* cline plugin install https://github.com/cline/cline/blob/main/sdk/examples/plugins/custom-compaction.ts --cwd .
* cline -i "Search the codebase for dispatcher usage, then summarize it"
*/

Some files were not shown because too many files have changed in this diff Show More