Compare commits

...

8 Commits

Author SHA1 Message Date
claude-code-best
956e98a445 fix: 修复重复依赖声明 2026-04-21 16:16:38 +08:00
claude-code-best
cee62bc654 fix: 修复 model alias 导致无限递归栈溢出
当用户 settings 中配置 model = "opus[1m]" 等 alias 值时,
getDefaultOpusModel() → parseUserSpecifiedModel() → getDefaultOpusModel()
形成无限递归,导致启动时 RangeError: Maximum call stack size exceeded。

在 getDefaultOpusModel/Sonnet/Haiku 的 fallback 路径中增加
isAliasOrAliasWithSuffix 守卫,跳过 alias 值直接使用硬编码默认值。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-21 16:10:16 +08:00
claude-code-best
5fc7c8e13d chore: 添加 highlight.js 包 2026-04-21 12:42:10 +08:00
claude-code-best
300faa18d0 Merge branch 'feature/unknown-llm-feature-test' 2026-04-21 12:06:19 +08:00
claude-code-best
96ec96c720 feat: 添加 ccb update 命令,支持 npm/bun 自动更新
从 package.json 读取当前版本,查询 npm registry 最新版本,
自动检测安装方式(bun 或 npm)执行全局更新。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 22:35:57 +08:00
claude-code-best
13a0bfc479 fix: 修复构建产物 import 失效问题 2026-04-20 22:29:44 +08:00
claude-code-best
84f0271813 chore: 1.7.1 2026-04-20 22:13:31 +08:00
claude-code-best
ed4bdb9338 feat: 增强 auto mode 的易用性 (#312)
* feat: poor 模式降级 yolo 审阅模型

* feat: 为多模块添加 Langfuse tracing 支持

在 web search、agent creation、away summary、token estimation、
skill improvement 等模块中集成 Langfuse trace,并透传至
compact/apiQueryHook/execPromptHook 等调用链。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 让 auto mode 记录回主 trace

* fix: reopen auto mode prompt when classifier is unavailable

* fix: 修复 auto mode 情况下, llm 报错导致弹窗也不打开的问题

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-20 21:13:09 +08:00
28 changed files with 942 additions and 262 deletions

View File

@@ -14,8 +14,9 @@
[文档在这里, 支持投稿 PR](https://ccb.agent-aura.top/) | [留影文档在这里](./Friends.md) | [Discord 群组](https://discord.gg/uApuzJWGKX) [文档在这里, 支持投稿 PR](https://ccb.agent-aura.top/) | [留影文档在这里](./Friends.md) | [Discord 群组](https://discord.gg/uApuzJWGKX)
| 特性 | 说明 | 文档 | | 特性 | 说明 | 文档 |
|------|------|------| | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Claude 群控技术** | Pipe IPC 多实例协作:同机 main/sub 自动编排 + LAN 跨机器零配置发现与通讯,`/pipes` 选择面板 + `Shift+↓` 交互 + 消息广播路由 | [Pipe IPC](https://ccb.agent-aura.top/docs/features/pipes-and-lan) / [LAN](https://ccb.agent-aura.top/docs/features/lan-pipes) | | **Claude 群控技术** | Pipe IPC 多实例协作:同机 main/sub 自动编排 + LAN 跨机器零配置发现与通讯,`/pipes` 选择面板 + `Shift+↓` 交互 + 消息广播路由 | [Pipe IPC](https://ccb.agent-aura.top/docs/features/pipes-and-lan) / [LAN](https://ccb.agent-aura.top/docs/features/lan-pipes) |
| **ACP 协议一等一支持** | 支持接入 Zed、Cursor 等 IDE支持会话恢复、Skills、权限桥接 | [文档](https://ccb.agent-aura.top/docs/features/acp-zed) | | **ACP 协议一等一支持** | 支持接入 Zed、Cursor 等 IDE支持会话恢复、Skills、权限桥接 | [文档](https://ccb.agent-aura.top/docs/features/acp-zed) |
| **Remote Control 私有部署** | Docker 自托管远程界面, 可以手机上看 CC | [文档](https://ccb.agent-aura.top/docs/features/remote-control-self-hosting) | | **Remote Control 私有部署** | Docker 自托管远程界面, 可以手机上看 CC | [文档](https://ccb.agent-aura.top/docs/features/remote-control-self-hosting) |
@@ -35,7 +36,6 @@
- 🐛 [想要调试项目](#vs-code-调试) - 🐛 [想要调试项目](#vs-code-调试)
- 📖 [想要学习项目](#teach-me-学习项目) - 📖 [想要学习项目](#teach-me-学习项目)
## ⚡ 快速开始(安装版) ## ⚡ 快速开始(安装版)
不用克隆仓库, 从 NPM 下载后, 直接使用 不用克隆仓库, 从 NPM 下载后, 直接使用
@@ -45,10 +45,11 @@ npm i -g claude-code-best
# bun 安装比较多问题, 推荐 npm 装 # bun 安装比较多问题, 推荐 npm 装
# bun i -g claude-code-best # bun i -g claude-code-best
# bun pm -g trust claude-code-best # bun pm -g trust claude-code-best @claude-code-best/mcp-chrome-bridge
ccb # 以 nodejs 打开 claude code ccb # 以 nodejs 打开 claude code
ccb-bun # 以 bun 形态打开 ccb-bun # 以 bun 形态打开
ccb update # 更新到最新版本
CLAUDE_BRIDGE_BASE_URL=https://remote-control.claude-code-best.win/ CLAUDE_BRIDGE_OAUTH_TOKEN=test-my-key ccb --remote-control # 我们有自部署的远程控制 CLAUDE_BRIDGE_BASE_URL=https://remote-control.claude-code-best.win/ CLAUDE_BRIDGE_OAUTH_TOKEN=test-my-key ccb --remote-control # 我们有自部署的远程控制
``` ```
@@ -90,8 +91,9 @@ bun run build
需要填写的字段: 需要填写的字段:
| 📌 字段 | 📝 说明 | 💡 示例 | | 📌 字段 | 📝 说明 | 💡 示例 |
|------|------|------| | ------------ | ------------- | ---------------------------- |
| Base URL | API 服务地址 | `https://api.example.com/v1` | | Base URL | API 服务地址 | `https://api.example.com/v1` |
| API Key | 认证密钥 | `sk-xxx` | | API Key | 认证密钥 | `sk-xxx` |
| Haiku Model | 快速模型 ID | `claude-haiku-4-5-20251001` | | Haiku Model | 快速模型 ID | `claude-haiku-4-5-20251001` |
@@ -100,7 +102,6 @@ bun run build
- ⌨️ **Tab / Shift+Tab** 切换字段,**Enter** 确认并跳到下一个,最后一个字段按 Enter 保存 - ⌨️ **Tab / Shift+Tab** 切换字段,**Enter** 确认并跳到下一个,最后一个字段按 Enter 保存
> 支持所有 Anthropic API 兼容服务(如 OpenRouter、AWS Bedrock 代理等),只要接口兼容 Messages API 即可。 > 支持所有 Anthropic API 兼容服务(如 OpenRouter、AWS Bedrock 代理等),只要接口兼容 Messages API 即可。
## Feature Flags ## Feature Flags
@@ -120,16 +121,17 @@ TUI (REPL) 模式需要真实终端,无法直接通过 VS Code launch 启动
### 步骤 ### 步骤
1. **终端启动 inspect 服务** 1. **终端启动 inspect 服务**
```bash ```bash
bun run dev:inspect bun run dev:inspect
``` ```
会输出类似 `ws://localhost:8888/xxxxxxxx` 的地址。
会输出类似 `ws://localhost:8888/xxxxxxxx` 的地址。
2. **VS Code 附着调试器** 2. **VS Code 附着调试器**
- 在 `src/` 文件中打断点 - 在 `src/` 文件中打断点
- F5 → 选择 **"Attach to Bun (TUI debug)"** - F5 → 选择 **"Attach to Bun (TUI debug)"**
## Teach Me 学习项目 ## Teach Me 学习项目
我们新加了一个 teach-me skills, 通过问答式引导帮你理解这个项目的任何模块。(调整 [sigma skill 而来](https://github.com/sanyuan0704/sanyuan-skills)) 我们新加了一个 teach-me skills, 通过问答式引导帮你理解这个项目的任何模块。(调整 [sigma skill 而来](https://github.com/sanyuan0704/sanyuan-skills))
@@ -156,7 +158,7 @@ TUI (REPL) 模式需要真实终端,无法直接通过 VS Code launch 启动
## 相关文档及网站 ## 相关文档及网站
- **在线文档Mintlify**: [ccb.agent-aura.top](https://ccb.agent-aura.top/) — 文档源码位于 [`docs/`](docs/) 目录,欢迎投稿 PR - **在线文档Mintlify**: [ccb.agent-aura.top](https://ccb.agent-aura.top/) — 文档源码位于 [`docs/`](docs/) 目录,欢迎投稿 PR
- **DeepWiki**: <https://deepwiki.com/claude-code-best/claude-code> - **DeepWiki**: [https://deepwiki.com/claude-code-best/claude-code](https://deepwiki.com/claude-code-best/claude-code)
## Contributors ## Contributors

View File

@@ -6,7 +6,8 @@
"name": "claude-code-best", "name": "claude-code-best",
"dependencies": { "dependencies": {
"@agentclientprotocol/sdk": "^0.19.0", "@agentclientprotocol/sdk": "^0.19.0",
"@claude-code-best/mcp-chrome-bridge": "^2.0.8", "@claude-code-best/mcp-chrome-bridge": "^3.0.1",
"highlight.js": "^11.11.1",
"ws": "^8.20.0", "ws": "^8.20.0",
}, },
"devDependencies": { "devDependencies": {
@@ -101,7 +102,6 @@
"get-east-asian-width": "^1.5.0", "get-east-asian-width": "^1.5.0",
"google-auth-library": "^10.6.2", "google-auth-library": "^10.6.2",
"he": "^1.2.0", "he": "^1.2.0",
"highlight.js": "^11.11.1",
"https-proxy-agent": "^8.0.0", "https-proxy-agent": "^8.0.0",
"ignore": "^7.0.5", "ignore": "^7.0.5",
"image-processor-napi": "workspace:*", "image-processor-napi": "workspace:*",
@@ -195,14 +195,13 @@
}, },
"packages/acp-link": { "packages/acp-link": {
"name": "acp-link", "name": "acp-link",
"version": "1.1.0", "version": "2.0.0",
"bin": { "bin": {
"acp-link": "dist/cli/bin.js", "acp-link": "dist/cli/bin.js",
"acp-manager": "dist/manager/bin.js",
}, },
"dependencies": { "dependencies": {
"@agentclientprotocol/sdk": "^0.19.0", "@agentclientprotocol/sdk": "^0.19.0",
"@hono/node-server": "^1.13.8", "@hono/node-server": "^2.0.0",
"@hono/node-ws": "^1.0.5", "@hono/node-ws": "^1.0.5",
"@stricli/auto-complete": "^1.2.4", "@stricli/auto-complete": "^1.2.4",
"@stricli/core": "^1.2.4", "@stricli/core": "^1.2.4",
@@ -265,6 +264,10 @@
"name": "modifiers-napi", "name": "modifiers-napi",
"version": "1.0.0", "version": "1.0.0",
}, },
"packages/pokemon": {
"name": "@claude-code-best/pokemon",
"version": "1.0.0",
},
"packages/remote-control-server": { "packages/remote-control-server": {
"name": "@anthropic/remote-control-server", "name": "@anthropic/remote-control-server",
"version": "0.1.0", "version": "0.1.0",
@@ -570,10 +573,12 @@
"@claude-code-best/builtin-tools": ["@claude-code-best/builtin-tools@workspace:packages/builtin-tools"], "@claude-code-best/builtin-tools": ["@claude-code-best/builtin-tools@workspace:packages/builtin-tools"],
"@claude-code-best/mcp-chrome-bridge": ["@claude-code-best/mcp-chrome-bridge@2.0.8", "https://registry.npmmirror.com/@claude-code-best/mcp-chrome-bridge/-/mcp-chrome-bridge-2.0.8.tgz", { "dependencies": { "@fastify/cors": "^11.0.1", "@modelcontextprotocol/sdk": "^1.11.0", "chalk": "^5.4.1", "chrome-mcp-shared": "^1.0.2", "commander": "^13.1.0", "fastify": "^5.3.2", "is-admin": "^4.0.0", "pino": "^9.6.0", "uuid": "^11.1.0" }, "bin": { "mcp-chrome-bridge": "dist/cli.js", "mcp-chrome-stdio": "dist/mcp/mcp-server-stdio.js" } }, "sha512-f7J1e4PQ6qxXzdHwL7QRrMZ4lPfD/L1MWxWDbyHmHY7jaW2GL6WcArKpk/fApg3V/q0racqUWzXHQdpE/HJZqg=="], "@claude-code-best/mcp-chrome-bridge": ["@claude-code-best/mcp-chrome-bridge@3.0.1", "", { "dependencies": { "@hono/node-server": "^1.19.13", "@modelcontextprotocol/sdk": "^1.11.0", "commander": "^13.1.0", "hono": "^4.12.12", "is-admin": "^4.0.0" }, "bin": { "mcp-chrome-bridge": "dist/cli.js", "mcp-chrome-stdio": "dist/mcp/mcp-server-stdio.js" } }, "sha512-ozeLHVOdckTUsWKJneJAL+CclrUlwVyBpfzFxgsrSL9f0LvjlJXE7+VcF5OmjDPwmZy6QNorvtg3/8NT2cIlzA=="],
"@claude-code-best/mcp-client": ["@claude-code-best/mcp-client@workspace:packages/mcp-client"], "@claude-code-best/mcp-client": ["@claude-code-best/mcp-client@workspace:packages/mcp-client"],
"@claude-code-best/pokemon": ["@claude-code-best/pokemon@workspace:packages/pokemon"],
"@claude-code-best/weixin": ["@claude-code-best/weixin@workspace:packages/weixin"], "@claude-code-best/weixin": ["@claude-code-best/weixin@workspace:packages/weixin"],
"@commander-js/extra-typings": ["@commander-js/extra-typings@14.0.0", "https://registry.npmmirror.com/@commander-js/extra-typings/-/extra-typings-14.0.0.tgz", { "peerDependencies": { "commander": "~14.0.0" } }, "sha512-hIn0ncNaJRLkZrxBIp5AsW/eXEHNKYQBh0aPdoUqNgD+Io3NIykQqpKFyKcuasZhicGaEZJX/JBSIkZ4e5x8Dg=="], "@commander-js/extra-typings": ["@commander-js/extra-typings@14.0.0", "https://registry.npmmirror.com/@commander-js/extra-typings/-/extra-typings-14.0.0.tgz", { "peerDependencies": { "commander": "~14.0.0" } }, "sha512-hIn0ncNaJRLkZrxBIp5AsW/eXEHNKYQBh0aPdoUqNgD+Io3NIykQqpKFyKcuasZhicGaEZJX/JBSIkZ4e5x8Dg=="],
@@ -636,22 +641,8 @@
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="], "@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.12", "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", { "os": "win32", "cpu": "x64" }, "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA=="],
"@fastify/ajv-compiler": ["@fastify/ajv-compiler@4.0.5", "https://registry.npmmirror.com/@fastify/ajv-compiler/-/ajv-compiler-4.0.5.tgz", { "dependencies": { "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0" } }, "sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A=="],
"@fastify/cors": ["@fastify/cors@11.2.0", "https://registry.npmmirror.com/@fastify/cors/-/cors-11.2.0.tgz", { "dependencies": { "fastify-plugin": "^5.0.0", "toad-cache": "^3.7.0" } }, "sha512-LbLHBuSAdGdSFZYTLVA3+Ch2t+sA6nq3Ejc6XLAKiQ6ViS2qFnvicpj0htsx03FyYeLs04HfRNBsz/a8SvbcUw=="],
"@fastify/error": ["@fastify/error@4.2.0", "https://registry.npmmirror.com/@fastify/error/-/error-4.2.0.tgz", {}, "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ=="],
"@fastify/fast-json-stringify-compiler": ["@fastify/fast-json-stringify-compiler@5.0.3", "https://registry.npmmirror.com/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.3.tgz", { "dependencies": { "fast-json-stringify": "^6.0.0" } }, "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ=="],
"@fastify/forwarded": ["@fastify/forwarded@3.0.1", "https://registry.npmmirror.com/@fastify/forwarded/-/forwarded-3.0.1.tgz", {}, "sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw=="],
"@fastify/merge-json-schemas": ["@fastify/merge-json-schemas@0.2.1", "https://registry.npmmirror.com/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A=="],
"@fastify/otel": ["@fastify/otel@0.18.0", "https://registry.npmmirror.com/@fastify/otel/-/otel-0.18.0.tgz", { "dependencies": { "@opentelemetry/core": "^2.0.0", "@opentelemetry/instrumentation": "^0.212.0", "@opentelemetry/semantic-conventions": "^1.28.0", "minimatch": "^10.2.4" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0" } }, "sha512-3TASCATfw+ctICSb4ymrv7iCm0qJ0N9CarB+CZ7zIJ7KqNbwI5JjyDL1/sxoC0ccTO1Zyd1iQ+oqncPg5FJXaA=="], "@fastify/otel": ["@fastify/otel@0.18.0", "https://registry.npmmirror.com/@fastify/otel/-/otel-0.18.0.tgz", { "dependencies": { "@opentelemetry/core": "^2.0.0", "@opentelemetry/instrumentation": "^0.212.0", "@opentelemetry/semantic-conventions": "^1.28.0", "minimatch": "^10.2.4" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0" } }, "sha512-3TASCATfw+ctICSb4ymrv7iCm0qJ0N9CarB+CZ7zIJ7KqNbwI5JjyDL1/sxoC0ccTO1Zyd1iQ+oqncPg5FJXaA=="],
"@fastify/proxy-addr": ["@fastify/proxy-addr@5.1.0", "https://registry.npmmirror.com/@fastify/proxy-addr/-/proxy-addr-5.1.0.tgz", { "dependencies": { "@fastify/forwarded": "^3.0.0", "ipaddr.js": "^2.1.0" } }, "sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw=="],
"@floating-ui/core": ["@floating-ui/core@1.7.5", "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.5.tgz", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], "@floating-ui/core": ["@floating-ui/core@1.7.5", "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.5.tgz", { "dependencies": { "@floating-ui/utils": "^0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="],
"@floating-ui/dom": ["@floating-ui/dom@1.7.6", "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.6.tgz", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.6.tgz", { "dependencies": { "@floating-ui/core": "^1.7.5", "@floating-ui/utils": "^0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="],
@@ -666,7 +657,7 @@
"@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "https://registry.npmmirror.com/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="], "@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "https://registry.npmmirror.com/@grpc/proto-loader/-/proto-loader-0.8.0.tgz", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="],
"@hono/node-server": ["@hono/node-server@1.19.13", "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.13.tgz", { "peerDependencies": { "hono": "^4" } }, "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ=="], "@hono/node-server": ["@hono/node-server@2.0.0", "", { "peerDependencies": { "hono": "^4" } }, "sha512-n3GfHwwCvHCkGmOwKfxUPOlbfzuO64Sbc5XC4NGPIXxkuOnJrdgExdRKmHfF924r914WRJPT397GdqLvdYTeyQ=="],
"@hono/node-ws": ["@hono/node-ws@1.3.0", "https://registry.npmmirror.com/@hono/node-ws/-/node-ws-1.3.0.tgz", { "dependencies": { "ws": "^8.17.0" }, "peerDependencies": { "@hono/node-server": "^1.19.2", "hono": "^4.6.0" } }, "sha512-ju25YbbvLuXdqBCmLZLqnNYu1nbHIQjoyUqA8ApZOeL1k4skuiTcw5SW77/5SUYo2Xi2NVBJoVlfQurnKEp03Q=="], "@hono/node-ws": ["@hono/node-ws@1.3.0", "https://registry.npmmirror.com/@hono/node-ws/-/node-ws-1.3.0.tgz", { "dependencies": { "ws": "^8.17.0" }, "peerDependencies": { "@hono/node-server": "^1.19.2", "hono": "^4.6.0" } }, "sha512-ju25YbbvLuXdqBCmLZLqnNYu1nbHIQjoyUqA8ApZOeL1k4skuiTcw5SW77/5SUYo2Xi2NVBJoVlfQurnKEp03Q=="],
@@ -1526,8 +1517,6 @@
"@xmldom/xmldom": ["@xmldom/xmldom@0.8.12", "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.12.tgz", {}, "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg=="], "@xmldom/xmldom": ["@xmldom/xmldom@0.8.12", "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.12.tgz", {}, "sha512-9k/gHF6n/pAi/9tqr3m3aqkuiNosYTurLLUtc7xQ9sxB/wm7WPygCv8GYa6mS0fLJEHhqMC1ATYhz++U/lRHqg=="],
"abstract-logging": ["abstract-logging@2.0.1", "https://registry.npmmirror.com/abstract-logging/-/abstract-logging-2.0.1.tgz", {}, "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA=="],
"accepts": ["accepts@2.0.0", "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], "accepts": ["accepts@2.0.0", "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
"acorn": ["acorn@8.16.0", "https://registry.npmmirror.com/acorn/-/acorn-8.16.0.tgz", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], "acorn": ["acorn@8.16.0", "https://registry.npmmirror.com/acorn/-/acorn-8.16.0.tgz", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="],
@@ -1568,8 +1557,6 @@
"auto-bind": ["auto-bind@5.0.1", "https://registry.npmmirror.com/auto-bind/-/auto-bind-5.0.1.tgz", {}, "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg=="], "auto-bind": ["auto-bind@5.0.1", "https://registry.npmmirror.com/auto-bind/-/auto-bind-5.0.1.tgz", {}, "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg=="],
"avvio": ["avvio@9.2.0", "https://registry.npmmirror.com/avvio/-/avvio-9.2.0.tgz", { "dependencies": { "@fastify/error": "^4.0.0", "fastq": "^1.17.1" } }, "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ=="],
"axios": ["axios@1.15.0", "https://registry.npmmirror.com/axios/-/axios-1.15.0.tgz", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q=="], "axios": ["axios@1.15.0", "https://registry.npmmirror.com/axios/-/axios-1.15.0.tgz", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^2.1.0" } }, "sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q=="],
"bail": ["bail@2.0.2", "https://registry.npmmirror.com/bail/-/bail-2.0.2.tgz", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], "bail": ["bail@2.0.2", "https://registry.npmmirror.com/bail/-/bail-2.0.2.tgz", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="],
@@ -1636,8 +1623,6 @@
"chokidar": ["chokidar@5.0.0", "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "chokidar": ["chokidar@5.0.0", "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
"chrome-mcp-shared": ["chrome-mcp-shared@1.0.2", "https://registry.npmmirror.com/chrome-mcp-shared/-/chrome-mcp-shared-1.0.2.tgz", { "dependencies": { "@modelcontextprotocol/sdk": "^1.11.0", "zod": "^3.24.4" } }, "sha512-v+6HBmcgXrIfyVbkkrVgfFDzqOfDutI8yZM0yA8k7SiicqL1MfBoqnsOy5idYNvxyQymxCxXNuTmajn8xaGsgQ=="],
"cjs-module-lexer": ["cjs-module-lexer@2.2.0", "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="], "cjs-module-lexer": ["cjs-module-lexer@2.2.0", "https://registry.npmmirror.com/cjs-module-lexer/-/cjs-module-lexer-2.2.0.tgz", {}, "sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ=="],
"class-variance-authority": ["class-variance-authority@0.7.1", "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="], "class-variance-authority": ["class-variance-authority@0.7.1", "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz", { "dependencies": { "clsx": "^2.1.1" } }, "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg=="],
@@ -1868,16 +1853,10 @@
"fast-copy": ["fast-copy@4.0.3", "https://registry.npmmirror.com/fast-copy/-/fast-copy-4.0.3.tgz", {}, "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw=="], "fast-copy": ["fast-copy@4.0.3", "https://registry.npmmirror.com/fast-copy/-/fast-copy-4.0.3.tgz", {}, "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw=="],
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "https://registry.npmmirror.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
"fast-deep-equal": ["fast-deep-equal@3.1.3", "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], "fast-deep-equal": ["fast-deep-equal@3.1.3", "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
"fast-glob": ["fast-glob@3.3.3", "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], "fast-glob": ["fast-glob@3.3.3", "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.3.3.tgz", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
"fast-json-stringify": ["fast-json-stringify@6.3.0", "https://registry.npmmirror.com/fast-json-stringify/-/fast-json-stringify-6.3.0.tgz", { "dependencies": { "@fastify/merge-json-schemas": "^0.2.0", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "fast-uri": "^3.0.0", "json-schema-ref-resolver": "^3.0.0", "rfdc": "^1.2.0" } }, "sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA=="],
"fast-querystring": ["fast-querystring@1.1.2", "https://registry.npmmirror.com/fast-querystring/-/fast-querystring-1.1.2.tgz", { "dependencies": { "fast-decode-uri-component": "^1.0.1" } }, "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg=="],
"fast-safe-stringify": ["fast-safe-stringify@2.1.1", "https://registry.npmmirror.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="], "fast-safe-stringify": ["fast-safe-stringify@2.1.1", "https://registry.npmmirror.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="],
"fast-uri": ["fast-uri@3.1.0", "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.0.tgz", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="], "fast-uri": ["fast-uri@3.1.0", "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.0.tgz", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
@@ -1886,10 +1865,6 @@
"fast-xml-parser": ["fast-xml-parser@5.5.8", "https://registry.npmmirror.com/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="], "fast-xml-parser": ["fast-xml-parser@5.5.8", "https://registry.npmmirror.com/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz", { "dependencies": { "fast-xml-builder": "^1.1.4", "path-expression-matcher": "^1.2.0", "strnum": "^2.2.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ=="],
"fastify": ["fastify@5.8.4", "https://registry.npmmirror.com/fastify/-/fastify-5.8.4.tgz", { "dependencies": { "@fastify/ajv-compiler": "^4.0.5", "@fastify/error": "^4.0.0", "@fastify/fast-json-stringify-compiler": "^5.0.0", "@fastify/proxy-addr": "^5.0.0", "abstract-logging": "^2.0.1", "avvio": "^9.0.0", "fast-json-stringify": "^6.0.0", "find-my-way": "^9.0.0", "light-my-request": "^6.0.0", "pino": "^9.14.0 || ^10.1.0", "process-warning": "^5.0.0", "rfdc": "^1.3.1", "secure-json-parse": "^4.0.0", "semver": "^7.6.0", "toad-cache": "^3.7.0" } }, "sha512-sa42J1xylbBAYUWALSBoyXKPDUvM3OoNOibIefA+Oha57FryXKKCZarA1iDntOCWp3O35voZLuDg2mdODXtPzQ=="],
"fastify-plugin": ["fastify-plugin@5.1.0", "https://registry.npmmirror.com/fastify-plugin/-/fastify-plugin-5.1.0.tgz", {}, "sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw=="],
"fastq": ["fastq@1.20.1", "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], "fastq": ["fastq@1.20.1", "https://registry.npmmirror.com/fastq/-/fastq-1.20.1.tgz", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
"fd-package-json": ["fd-package-json@2.0.0", "https://registry.npmmirror.com/fd-package-json/-/fd-package-json-2.0.0.tgz", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="], "fd-package-json": ["fd-package-json@2.0.0", "https://registry.npmmirror.com/fd-package-json/-/fd-package-json-2.0.0.tgz", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="],
@@ -1906,8 +1881,6 @@
"finalhandler": ["finalhandler@2.1.1", "https://registry.npmmirror.com/finalhandler/-/finalhandler-2.1.1.tgz", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], "finalhandler": ["finalhandler@2.1.1", "https://registry.npmmirror.com/finalhandler/-/finalhandler-2.1.1.tgz", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
"find-my-way": ["find-my-way@9.5.0", "https://registry.npmmirror.com/find-my-way/-/find-my-way-9.5.0.tgz", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-querystring": "^1.0.0", "safe-regex2": "^5.0.0" } }, "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ=="],
"find-up": ["find-up@4.1.0", "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="], "find-up": ["find-up@4.1.0", "https://registry.npmmirror.com/find-up/-/find-up-4.1.0.tgz", { "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" } }, "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="],
"flora-colossus": ["flora-colossus@2.0.0", "https://registry.npmmirror.com/flora-colossus/-/flora-colossus-2.0.0.tgz", { "dependencies": { "debug": "^4.3.4", "fs-extra": "^10.1.0" } }, "sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA=="], "flora-colossus": ["flora-colossus@2.0.0", "https://registry.npmmirror.com/flora-colossus/-/flora-colossus-2.0.0.tgz", { "dependencies": { "debug": "^4.3.4", "fs-extra": "^10.1.0" } }, "sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA=="],
@@ -2106,8 +2079,6 @@
"json-schema": ["json-schema@0.4.0", "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="], "json-schema": ["json-schema@0.4.0", "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz", {}, "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="],
"json-schema-ref-resolver": ["json-schema-ref-resolver@3.0.0", "https://registry.npmmirror.com/json-schema-ref-resolver/-/json-schema-ref-resolver-3.0.0.tgz", { "dependencies": { "dequal": "^2.0.3" } }, "sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A=="],
"json-schema-to-ts": ["json-schema-to-ts@3.1.1", "https://registry.npmmirror.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="], "json-schema-to-ts": ["json-schema-to-ts@3.1.1", "https://registry.npmmirror.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", { "dependencies": { "@babel/runtime": "^7.18.3", "ts-algebra": "^2.0.0" } }, "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g=="],
"json-schema-traverse": ["json-schema-traverse@1.0.0", "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], "json-schema-traverse": ["json-schema-traverse@1.0.0", "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
@@ -2138,8 +2109,6 @@
"layout-base": ["layout-base@1.0.2", "https://registry.npmmirror.com/layout-base/-/layout-base-1.0.2.tgz", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="], "layout-base": ["layout-base@1.0.2", "https://registry.npmmirror.com/layout-base/-/layout-base-1.0.2.tgz", {}, "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg=="],
"light-my-request": ["light-my-request@6.6.0", "https://registry.npmmirror.com/light-my-request/-/light-my-request-6.6.0.tgz", { "dependencies": { "cookie": "^1.0.1", "process-warning": "^4.0.0", "set-cookie-parser": "^2.6.0" } }, "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A=="],
"lightningcss": ["lightningcss@1.32.0", "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="], "lightningcss": ["lightningcss@1.32.0", "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.32.0.tgz", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="], "lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
@@ -2564,14 +2533,10 @@
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "https://registry.npmmirror.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"ret": ["ret@0.5.0", "https://registry.npmmirror.com/ret/-/ret-0.5.0.tgz", {}, "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw=="],
"retry": ["retry@0.12.0", "https://registry.npmmirror.com/retry/-/retry-0.12.0.tgz", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], "retry": ["retry@0.12.0", "https://registry.npmmirror.com/retry/-/retry-0.12.0.tgz", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="],
"reusify": ["reusify@1.1.0", "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], "reusify": ["reusify@1.1.0", "https://registry.npmmirror.com/reusify/-/reusify-1.1.0.tgz", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
"rfdc": ["rfdc@1.4.1", "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz", {}, "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA=="],
"robust-predicates": ["robust-predicates@3.0.3", "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.3.tgz", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="], "robust-predicates": ["robust-predicates@3.0.3", "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.3.tgz", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="],
"rolldown": ["rolldown@1.0.0-rc.15", "https://registry.npmmirror.com/rolldown/-/rolldown-1.0.0-rc.15.tgz", { "dependencies": { "@oxc-project/types": "=0.124.0", "@rolldown/pluginutils": "1.0.0-rc.15" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-x64": "1.0.0-rc.15", "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g=="], "rolldown": ["rolldown@1.0.0-rc.15", "https://registry.npmmirror.com/rolldown/-/rolldown-1.0.0-rc.15.tgz", { "dependencies": { "@oxc-project/types": "=0.124.0", "@rolldown/pluginutils": "1.0.0-rc.15" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", "@rolldown/binding-darwin-x64": "1.0.0-rc.15", "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g=="],
@@ -2590,8 +2555,6 @@
"safe-buffer": ["safe-buffer@5.2.1", "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], "safe-buffer": ["safe-buffer@5.2.1", "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
"safe-regex2": ["safe-regex2@5.1.0", "https://registry.npmmirror.com/safe-regex2/-/safe-regex2-5.1.0.tgz", { "dependencies": { "ret": "~0.5.0" }, "bin": { "safe-regex2": "bin/safe-regex2.js" } }, "sha512-pNHAuBW7TrcleFHsxBr5QMi/Iyp0ENjUKz7GCcX1UO7cMh+NmVK6HxQckNL1tJp1XAJVjG6B8OKIPqodqj9rtw=="],
"safe-stable-stringify": ["safe-stable-stringify@2.5.0", "https://registry.npmmirror.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="], "safe-stable-stringify": ["safe-stable-stringify@2.5.0", "https://registry.npmmirror.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", {}, "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA=="],
"safer-buffer": ["safer-buffer@2.1.2", "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], "safer-buffer": ["safer-buffer@2.1.2", "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
@@ -2610,8 +2573,6 @@
"set-blocking": ["set-blocking@2.0.0", "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="], "set-blocking": ["set-blocking@2.0.0", "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", {}, "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="],
"set-cookie-parser": ["set-cookie-parser@2.7.2", "https://registry.npmmirror.com/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="],
"setprototypeof": ["setprototypeof@1.2.0", "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], "setprototypeof": ["setprototypeof@1.2.0", "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
"sharp": ["sharp@0.34.5", "https://registry.npmmirror.com/sharp/-/sharp-0.34.5.tgz", { "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=="], "sharp": ["sharp@0.34.5", "https://registry.npmmirror.com/sharp/-/sharp-0.34.5.tgz", { "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=="],
@@ -2702,8 +2663,6 @@
"to-regex-range": ["to-regex-range@5.0.1", "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], "to-regex-range": ["to-regex-range@5.0.1", "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
"toad-cache": ["toad-cache@3.7.0", "https://registry.npmmirror.com/toad-cache/-/toad-cache-3.7.0.tgz", {}, "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw=="],
"toidentifier": ["toidentifier@1.0.1", "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], "toidentifier": ["toidentifier@1.0.1", "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
"tr46": ["tr46@0.0.3", "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "tr46": ["tr46@0.0.3", "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="],
@@ -3064,7 +3023,7 @@
"@claude-code-best/agent-tools/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], "@claude-code-best/agent-tools/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"@claude-code-best/mcp-chrome-bridge/pino": ["pino@9.14.0", "https://registry.npmmirror.com/pino/-/pino-9.14.0.tgz", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w=="], "@claude-code-best/mcp-chrome-bridge/@hono/node-server": ["@hono/node-server@1.19.13", "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.13.tgz", { "peerDependencies": { "hono": "^4" } }, "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ=="],
"@claude-code-best/mcp-client/lru-cache": ["lru-cache@10.4.3", "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "@claude-code-best/mcp-client/lru-cache": ["lru-cache@10.4.3", "https://registry.npmmirror.com/lru-cache/-/lru-cache-10.4.3.tgz", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="],
@@ -3076,16 +3035,18 @@
"@fastify/otel/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.212.0", "https://registry.npmmirror.com/@opentelemetry/instrumentation/-/instrumentation-0.212.0.tgz", { "dependencies": { "@opentelemetry/api-logs": "0.212.0", "import-in-the-middle": "^2.0.6", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg=="], "@fastify/otel/@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.212.0", "https://registry.npmmirror.com/@opentelemetry/instrumentation/-/instrumentation-0.212.0.tgz", { "dependencies": { "@opentelemetry/api-logs": "0.212.0", "import-in-the-middle": "^2.0.6", "require-in-the-middle": "^8.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IyXmpNnifNouMOe0I/gX7ENfv2ZCNdYTF0FpCsoBcpbIHzk81Ww9rQTYTnvghszCg7qGrIhNvWC8dhEifgX9Jg=="],
"@fastify/proxy-addr/ipaddr.js": ["ipaddr.js@2.3.0", "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-2.3.0.tgz", {}, "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg=="],
"@grpc/proto-loader/yargs": ["yargs@17.7.2", "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], "@grpc/proto-loader/yargs": ["yargs@17.7.2", "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
"@hono/node-ws/@hono/node-server": ["@hono/node-server@1.19.13", "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.13.tgz", { "peerDependencies": { "hono": "^4" } }, "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ=="],
"@inquirer/core/@types/node": ["@types/node@22.19.17", "https://registry.npmmirror.com/@types/node/-/node-22.19.17.tgz", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q=="], "@inquirer/core/@types/node": ["@types/node@22.19.17", "https://registry.npmmirror.com/@types/node/-/node-22.19.17.tgz", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q=="],
"@inquirer/core/strip-ansi": ["strip-ansi@6.0.1", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], "@inquirer/core/strip-ansi": ["strip-ansi@6.0.1", "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="], "@inquirer/core/wrap-ansi": ["wrap-ansi@6.2.0", "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
"@modelcontextprotocol/sdk/@hono/node-server": ["@hono/node-server@1.19.13", "https://registry.npmmirror.com/@hono/node-server/-/node-server-1.19.13.tgz", { "peerDependencies": { "hono": "^4" } }, "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ=="],
"@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.6.1", "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.6.1.tgz", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g=="], "@opentelemetry/exporter-logs-otlp-grpc/@opentelemetry/core": ["@opentelemetry/core@2.6.1", "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.6.1.tgz", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g=="],
"@opentelemetry/exporter-logs-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.6.1", "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.6.1.tgz", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g=="], "@opentelemetry/exporter-logs-otlp-http/@opentelemetry/core": ["@opentelemetry/core@2.6.1", "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.6.1.tgz", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-8xHSGWpJP9wBxgBpnqGL0R3PbdWQndL1Qp50qrg71+B28zK5OQmUgcDKLJgzyAAV38t4tOyLMGDD60LneR5W8g=="],
@@ -3338,8 +3299,6 @@
"cacache/lru-cache": ["lru-cache@11.3.3", "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.3.3.tgz", {}, "sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ=="], "cacache/lru-cache": ["lru-cache@11.3.3", "https://registry.npmmirror.com/lru-cache/-/lru-cache-11.3.3.tgz", {}, "sha512-JvNw9Y81y33E+BEYPr0U7omo+U9AySnsMsEiXgwT6yqd31VQWTLNQqmT4ou5eqPFUrTfIDFta2wKhB1hyohtAQ=="],
"chrome-mcp-shared/zod": ["zod@3.25.76", "https://registry.npmmirror.com/zod/-/zod-3.25.76.tgz", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="],
"cli-highlight/chalk": ["chalk@4.1.2", "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "cli-highlight/chalk": ["chalk@4.1.2", "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
"cli-highlight/highlight.js": ["highlight.js@10.7.3", "https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="], "cli-highlight/highlight.js": ["highlight.js@10.7.3", "https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
@@ -3362,8 +3321,6 @@
"external-editor/iconv-lite": ["iconv-lite@0.4.24", "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="], "external-editor/iconv-lite": ["iconv-lite@0.4.24", "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3" } }, "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="],
"fastify/pino": ["pino@9.14.0", "https://registry.npmmirror.com/pino/-/pino-9.14.0.tgz", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^2.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^3.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w=="],
"form-data/mime-types": ["mime-types@2.1.35", "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], "form-data/mime-types": ["mime-types@2.1.35", "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="],
"gaxios/https-proxy-agent": ["https-proxy-agent@7.0.6", "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], "gaxios/https-proxy-agent": ["https-proxy-agent@7.0.6", "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="],
@@ -3382,10 +3339,6 @@
"katex/commander": ["commander@8.3.0", "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], "katex/commander": ["commander@8.3.0", "https://registry.npmmirror.com/commander/-/commander-8.3.0.tgz", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="],
"light-my-request/cookie": ["cookie@1.1.1", "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="],
"light-my-request/process-warning": ["process-warning@4.0.1", "https://registry.npmmirror.com/process-warning/-/process-warning-4.0.1.tgz", {}, "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q=="],
"mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="],
"mermaid/marked": ["marked@16.4.2", "https://registry.npmmirror.com/marked/-/marked-16.4.2.tgz", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="], "mermaid/marked": ["marked@16.4.2", "https://registry.npmmirror.com/marked/-/marked-16.4.2.tgz", { "bin": { "marked": "bin/marked.js" } }, "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA=="],
@@ -3634,10 +3587,6 @@
"@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="],
"@claude-code-best/mcp-chrome-bridge/pino/pino-abstract-transport": ["pino-abstract-transport@2.0.0", "https://registry.npmmirror.com/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="],
"@claude-code-best/mcp-chrome-bridge/pino/thread-stream": ["thread-stream@3.1.0", "https://registry.npmmirror.com/thread-stream/-/thread-stream-3.1.0.tgz", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
"@fastify/otel/@opentelemetry/instrumentation/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.212.0", "https://registry.npmmirror.com/@opentelemetry/api-logs/-/api-logs-0.212.0.tgz", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg=="], "@fastify/otel/@opentelemetry/instrumentation/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.212.0", "https://registry.npmmirror.com/@opentelemetry/api-logs/-/api-logs-0.212.0.tgz", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-TEEVrLbNROUkYY51sBJGk7lO/OLjuepch8+hmpM6ffMJQ2z/KVCjdHuCFX6fJj8OkJP2zckPjrJzQtXU3IAsFg=="],
"@fastify/otel/@opentelemetry/instrumentation/import-in-the-middle": ["import-in-the-middle@2.0.6", "https://registry.npmmirror.com/import-in-the-middle/-/import-in-the-middle-2.0.6.tgz", { "dependencies": { "acorn": "^8.15.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw=="], "@fastify/otel/@opentelemetry/instrumentation/import-in-the-middle": ["import-in-the-middle@2.0.6", "https://registry.npmmirror.com/import-in-the-middle/-/import-in-the-middle-2.0.6.tgz", { "dependencies": { "acorn": "^8.15.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^2.2.0", "module-details-from-path": "^1.0.4" } }, "sha512-3vZV3jX0XRFW3EJDTwzWoZa+RH1b8eTTx6YOCjglrLyPuepwoBti1k3L2dKwdCUrnVEfc5CuRuGstaC/uQJJaw=="],
@@ -3720,10 +3669,6 @@
"d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "https://registry.npmmirror.com/d3-path/-/d3-path-1.0.9.tgz", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="], "d3-sankey/d3-shape/d3-path": ["d3-path@1.0.9", "https://registry.npmmirror.com/d3-path/-/d3-path-1.0.9.tgz", {}, "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg=="],
"fastify/pino/pino-abstract-transport": ["pino-abstract-transport@2.0.0", "https://registry.npmmirror.com/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", { "dependencies": { "split2": "^4.0.0" } }, "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw=="],
"fastify/pino/thread-stream": ["thread-stream@3.1.0", "https://registry.npmmirror.com/thread-stream/-/thread-stream-3.1.0.tgz", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="],
"form-data/mime-types/mime-db": ["mime-db@1.52.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], "form-data/mime-types/mime-db": ["mime-db@1.52.0", "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="],
"gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.4", "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], "gaxios/https-proxy-agent/agent-base": ["agent-base@7.1.4", "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],

View File

@@ -1,6 +1,6 @@
{ {
"name": "claude-code-best", "name": "claude-code-best",
"version": "1.6.0", "version": "1.8.0",
"description": "Reverse-engineered Anthropic Claude Code CLI — interactive AI coding assistant in the terminal", "description": "Reverse-engineered Anthropic Claude Code CLI — interactive AI coding assistant in the terminal",
"type": "module", "type": "module",
"author": "claude-code-best <claude-code-best@proton.me>", "author": "claude-code-best <claude-code-best@proton.me>",
@@ -53,6 +53,7 @@
"format": "biome format --write src/", "format": "biome format --write src/",
"prepare": "git config core.hooksPath .githooks", "prepare": "git config core.hooksPath .githooks",
"test": "bun test", "test": "bun test",
"check:bundle": "bun run scripts/check-bundle-integrity.ts",
"check:unused": "knip-bun", "check:unused": "knip-bun",
"health": "bun run scripts/health-check.ts", "health": "bun run scripts/health-check.ts",
"postinstall": "node scripts/run-parallel.mjs scripts/postinstall.cjs scripts/setup-chrome-mcp.mjs", "postinstall": "node scripts/run-parallel.mjs scripts/postinstall.cjs scripts/setup-chrome-mcp.mjs",
@@ -63,7 +64,8 @@
}, },
"dependencies": { "dependencies": {
"@agentclientprotocol/sdk": "^0.19.0", "@agentclientprotocol/sdk": "^0.19.0",
"@claude-code-best/mcp-chrome-bridge": "^2.0.8", "@claude-code-best/mcp-chrome-bridge": "^3.0.1",
"highlight.js": "^11.11.1",
"ws": "^8.20.0" "ws": "^8.20.0"
}, },
"devDependencies": { "devDependencies": {
@@ -158,7 +160,6 @@
"get-east-asian-width": "^1.5.0", "get-east-asian-width": "^1.5.0",
"google-auth-library": "^10.6.2", "google-auth-library": "^10.6.2",
"he": "^1.2.0", "he": "^1.2.0",
"highlight.js": "^11.11.1",
"https-proxy-agent": "^8.0.0", "https-proxy-agent": "^8.0.0",
"ignore": "^7.0.5", "ignore": "^7.0.5",
"image-processor-napi": "workspace:*", "image-processor-napi": "workspace:*",

View File

@@ -26,7 +26,7 @@
}, },
"dependencies": { "dependencies": {
"@agentclientprotocol/sdk": "^0.19.0", "@agentclientprotocol/sdk": "^0.19.0",
"@hono/node-server": "^1.13.8", "@hono/node-server": "^2.0.0",
"@hono/node-ws": "^1.0.5", "@hono/node-ws": "^1.0.5",
"@stricli/auto-complete": "^1.2.4", "@stricli/auto-complete": "^1.2.4",
"@stricli/core": "^1.2.4", "@stricli/core": "^1.2.4",

View File

@@ -9,6 +9,9 @@ import type {
} from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs' } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js' import { getFeatureValue_CACHED_MAY_BE_STALE } from 'src/services/analytics/growthbook.js'
import { queryModelWithStreaming } from 'src/services/api/claude.js' import { queryModelWithStreaming } from 'src/services/api/claude.js'
import { createTrace, endTrace, isLangfuseEnabled } from 'src/services/langfuse/index.js'
import { getSessionId } from 'src/bootstrap/state.js'
import { getAPIProvider } from 'src/utils/model/providers.js'
import { createUserMessage } from 'src/utils/messages.js' import { createUserMessage } from 'src/utils/messages.js'
import { getMainLoopModel, getSmallFastModel } from 'src/utils/model/model.js' import { getMainLoopModel, getSmallFastModel } from 'src/utils/model/model.js'
import { jsonParse } from 'src/utils/slowOperations.js' import { jsonParse } from 'src/utils/slowOperations.js'
@@ -38,6 +41,15 @@ export class ApiSearchAdapter implements WebSearchAdapter {
const toolSchema = makeToolSchema({ allowedDomains, blockedDomains }) const toolSchema = makeToolSchema({ allowedDomains, blockedDomains })
const useHaiku = getFeatureValue_CACHED_MAY_BE_STALE('tengu_plum_vx3', false) const useHaiku = getFeatureValue_CACHED_MAY_BE_STALE('tengu_plum_vx3', false)
const model = useHaiku ? getSmallFastModel() : getMainLoopModel()
const langfuseTrace = isLangfuseEnabled()
? createTrace({
sessionId: getSessionId(),
model,
provider: getAPIProvider(),
name: 'web-search-tool',
})
: null
const queryStream = queryModelWithStreaming({ const queryStream = queryModelWithStreaming({
messages: [userMessage], messages: [userMessage],
@@ -58,7 +70,7 @@ export class ApiSearchAdapter implements WebSearchAdapter {
alwaysAskRules: {}, alwaysAskRules: {},
isBypassPermissionsModeAvailable: false, isBypassPermissionsModeAvailable: false,
}), }),
model: useHaiku ? getSmallFastModel() : getMainLoopModel(), model,
toolChoice: useHaiku ? { type: 'tool' as const, name: 'web_search' } : undefined, toolChoice: useHaiku ? { type: 'tool' as const, name: 'web_search' } : undefined,
isNonInteractiveSession: false, isNonInteractiveSession: false,
hasAppendSystemPrompt: false, hasAppendSystemPrompt: false,
@@ -68,6 +80,7 @@ export class ApiSearchAdapter implements WebSearchAdapter {
mcpTools: [], mcpTools: [],
agentId: undefined, agentId: undefined,
effortValue: undefined, effortValue: undefined,
langfuseTrace,
}, },
}) })
@@ -148,6 +161,8 @@ export class ApiSearchAdapter implements WebSearchAdapter {
} }
} }
endTrace(langfuseTrace)
// Extract SearchResult[] from content blocks // Extract SearchResult[] from content blocks
return extractSearchResults(allContentBlocks) return extractSearchResults(allContentBlocks)
} }

View File

@@ -0,0 +1,336 @@
#!/usr/bin/env bun
/**
* 构建产物完整性检查脚本
*
* 检查 Bun.build({ splitting: true }) 输出的 dist/ 目录中是否存在:
* 1. 引用了不存在的 chunk 文件(断链)
* 2. 通过 __require() 或 import() 引用的第三方模块(非 Node.js 内置),在生产环境中会找不到
* 3. 缺失的静态 import 依赖(跨 chunk 引用目标不存在)
*
* 用法:
* bun scripts/check-bundle-integrity.ts # 检查当前 dist/
* bun scripts/check-bundle-integrity.ts ./dist # 指定目录
*/
import { readdir, readFile } from "fs/promises"
import { join, resolve, dirname } from "path"
import { fileURLToPath } from "url"
// ─── 从 package.json 读取 dependencies 作为白名单 ────────────────
const __dirname = dirname(fileURLToPath(import.meta.url))
const pkg = JSON.parse(await readFile(join(__dirname, '..', 'package.json'), 'utf-8'))
const PKG_DEPS = new Set(Object.keys(pkg.dependencies ?? {}))
// ─── Node.js 内置模块白名单 ────────────────────────────────────────
const NODE_BUILTINS = new Set([
"assert",
"async_hooks",
"buffer",
"child_process",
"cluster",
"console",
"constants",
"crypto",
"dgram",
"diagnostics_channel",
"dns",
"domain",
"events",
"fs",
"fs/promises",
"http",
"http2",
"https",
"inspector",
"module",
"net",
"os",
"path",
"perf_hooks",
"process",
"punycode",
"querystring",
"readline",
"repl",
"stream",
"string_decoder",
"sys",
"timers",
"tls",
"tty",
"url",
"util",
"v8",
"vm",
"worker_threads",
"zlib",
"node:test",
])
// Node 18+ 内置但不在传统列表中的模块
const NODE_18_PLUS_BUILTINS = new Set(["undici"])
// Bun 专用模块(仅在 Bun 运行时可用Node.js 环境会失败)
const BUN_MODULES = new Set(["bun", "bun:ffi", "bun:test", "bun:sqlite"])
// macOS JXA / native 框架(通过 ObjC.import非真正的 require
const NATIVE_FRAMEWORKS = new Set(["AppKit", "CoreGraphics", "Foundation", "UIKit"])
// ─── 模式 ──────────────────────────────────────────────────────────
// 匹配 import { ... } from "./chunk-xxxxx.js" 或 import"./chunk-xxxxx.js"
const STATIC_IMPORT_RE = /(?:from\s+|import\s+)"(\.\/[^"]+\.js)"/g
// 匹配 __require("xxx")
const REQUIRE_RE = /__require\("([^"]+)"\)/g
// 匹配动态 import("xxx"),排除 ./chunk-xxx.js 的内部引用
const DYNAMIC_IMPORT_RE = /import\("([^"]+)"\)/g
// 匹配 nodeRequire("xxx")createRequire 创建的 require 别名)
const NODE_REQUIRE_RE = /nodeRequire\("([^"]+)"\)/g
interface Finding {
type: "broken-chunk-ref" | "third-party-require" | "third-party-import" | "third-party-node-require" | "bun-runtime-only"
severity: "error" | "warning"
file: string
line: number
module: string
snippet: string
}
async function main() {
const distDir = resolve(process.argv[2] || "./dist")
console.log(`\n🔍 检查构建产物完整性: ${distDir}\n`)
// 1. 列出所有 chunk 文件
let files: string[]
try {
files = (await readdir(distDir)).filter((f) => f.endsWith(".js"))
} catch {
console.error(`❌ 无法读取目录: ${distDir}`)
console.error(" 请先运行 bun run build")
process.exit(1)
}
const fileSet = new Set(files)
console.log(`📦 找到 ${files.length} 个 JS 文件\n`)
const findings: Finding[] = []
// 2. 逐文件扫描
for (const file of files) {
const filePath = join(distDir, file)
const content = await readFile(filePath, "utf-8")
const lines = content.split("\n")
for (let i = 0; i < lines.length; i++) {
const line = lines[i]
const lineNum = i + 1
// 2a. 检查静态 chunk 引用是否断链
const staticImportMatches = line.matchAll(STATIC_IMPORT_RE)
for (const m of staticImportMatches) {
const ref = m[1]
// 提取文件名部分(去掉 ./
const refFile = ref.replace(/^\.\//, "")
if (!fileSet.has(refFile)) {
findings.push({
type: "broken-chunk-ref",
severity: "error",
file,
line: lineNum,
module: ref,
snippet: line.trim().slice(0, 120),
})
}
}
// 2b. 检查 __require 中的第三方模块
const requireMatches = line.matchAll(REQUIRE_RE)
for (const m of requireMatches) {
const mod = m[1]
// 跳过 ObjC.importJXA 语法,不是真正的 require
if (NATIVE_FRAMEWORKS.has(mod)) continue
if (NODE_BUILTINS.has(mod) || NODE_18_PLUS_BUILTINS.has(mod) || PKG_DEPS.has(mod) || mod.startsWith("node:")) continue
if (BUN_MODULES.has(mod)) {
findings.push({
type: "bun-runtime-only",
severity: "warning",
file,
line: lineNum,
module: mod,
snippet: line.trim().slice(0, 120),
})
continue
}
// 第三方模块 — 在生产环境(全局 npm install中找不到
findings.push({
type: "third-party-require",
severity: "error",
file,
line: lineNum,
module: mod,
snippet: line.trim().slice(0, 120),
})
}
// 2c. 检查动态 import() 中的第三方模块
const dynImportMatches = line.matchAll(DYNAMIC_IMPORT_RE)
for (const m of dynImportMatches) {
const mod = m[1]
// 跳过内部 chunk 引用和相对路径
if (mod.startsWith("./") || mod.startsWith("../")) continue
// 跳过 ObjC.import
if (NATIVE_FRAMEWORKS.has(mod)) continue
if (NODE_BUILTINS.has(mod) || NODE_18_PLUS_BUILTINS.has(mod) || PKG_DEPS.has(mod) || mod.startsWith("node:")) continue
if (BUN_MODULES.has(mod)) {
// bun:test 等只在 Bun 运行时可用Node.js 运行时会失败
findings.push({
type: "bun-runtime-only",
severity: "warning",
file,
line: lineNum,
module: mod,
snippet: line.trim().slice(0, 120),
})
continue
}
// 第三方动态 import
findings.push({
type: "third-party-import",
severity: "error",
file,
line: lineNum,
module: mod,
snippet: line.trim().slice(0, 120),
})
}
// 2d. 检查 nodeRequire("xxx") 中的第三方模块createRequire 别名)
const nodeRequireMatches = line.matchAll(NODE_REQUIRE_RE)
for (const m of nodeRequireMatches) {
const mod = m[1]
if (NATIVE_FRAMEWORKS.has(mod)) continue
if (NODE_BUILTINS.has(mod) || NODE_18_PLUS_BUILTINS.has(mod) || PKG_DEPS.has(mod) || mod.startsWith("node:")) continue
if (BUN_MODULES.has(mod)) {
findings.push({
type: "bun-runtime-only",
severity: "warning",
file,
line: lineNum,
module: mod,
snippet: line.trim().slice(0, 120),
})
continue
}
findings.push({
type: "third-party-node-require",
severity: "error",
file,
line: lineNum,
module: mod,
snippet: line.trim().slice(0, 120),
})
}
}
}
// 3. 汇总报告
const errors = findings.filter((f) => f.severity === "error")
const warnings = findings.filter((f) => f.severity === "warning")
// 按 type 分组
const brokenRefs = errors.filter((f) => f.type === "broken-chunk-ref")
const thirdPartyRequires = errors.filter((f) => f.type === "third-party-require")
const thirdPartyImports = errors.filter((f) => f.type === "third-party-import")
const thirdPartyNodeRequires = errors.filter((f) => f.type === "third-party-node-require")
const bunRuntimeOnly = warnings.filter((f) => f.type === "bun-runtime-only")
if (brokenRefs.length > 0) {
console.log("❌ 断裂的 chunk 引用(引用了不存在的文件):")
for (const f of brokenRefs) {
console.log(` ${f.file}:${f.line}${f.module}`)
}
console.log()
}
if (thirdPartyRequires.length > 0) {
console.log("❌ 通过 __require() 引用的第三方模块(生产环境会找不到):")
const grouped = groupByModule(thirdPartyRequires)
for (const [mod, items] of grouped) {
console.log(` "${mod}" — 出现 ${items.length} 次:`)
for (const f of items.slice(0, 5)) {
console.log(` ${f.file}:${f.line}`)
}
if (items.length > 5) console.log(` ... 还有 ${items.length - 5}`)
}
console.log()
}
if (thirdPartyImports.length > 0) {
console.log("❌ 通过 import() 动态引用的第三方模块(生产环境会找不到):")
const grouped = groupByModule(thirdPartyImports)
for (const [mod, items] of grouped) {
console.log(` "${mod}" — 出现 ${items.length} 次:`)
for (const f of items.slice(0, 5)) {
console.log(` ${f.file}:${f.line}`)
}
if (items.length > 5) console.log(` ... 还有 ${items.length - 5}`)
}
console.log()
}
if (thirdPartyNodeRequires.length > 0) {
console.log("❌ 通过 nodeRequire() 引用的第三方模块(绕过打包,生产环境会找不到):")
const grouped = groupByModule(thirdPartyNodeRequires)
for (const [mod, items] of grouped) {
console.log(` "${mod}" — 出现 ${items.length} 次:`)
for (const f of items.slice(0, 5)) {
console.log(` ${f.file}:${f.line}`)
}
if (items.length > 5) console.log(` ... 还有 ${items.length - 5}`)
}
console.log()
}
if (bunRuntimeOnly.length > 0) {
console.log("⚠️ Bun 运行时专用模块Node.js 环境会失败):")
const grouped = groupByModule(bunRuntimeOnly)
for (const [mod, items] of grouped) {
console.log(` "${mod}" — 出现 ${items.length}`)
}
console.log()
}
// 4. 总结
console.log("─".repeat(50))
if (errors.length === 0 && warnings.length === 0) {
console.log("✅ 构建产物完整性检查通过,未发现问题。")
} else {
console.log(`📊 总计: ${errors.length} 个错误, ${warnings.length} 个警告`)
if (errors.length > 0) {
console.log(
`\n💡 修复建议:
- 第三方模块问题:在 build.ts 中通过 external 选项排除,或确保它们被正确打包到 chunk 中
- 断链问题:检查 build 时是否有文件被意外删除或构建不完整
- Bun 专用模块:确保运行时使用 bun 而非 node`,
)
}
}
process.exit(errors.length > 0 ? 1 : 0)
}
function groupByModule(items: Finding[]): Map<string, Finding[]> {
const map = new Map<string, Finding[]>()
for (const item of items) {
const list = map.get(item.module) || []
list.push(item)
map.set(item.module, list)
}
// 按出现次数降序
return new Map([...map.entries()].sort((a, b) => b[1].length - a[1].length))
}
main().catch((err) => {
console.error("Fatal error:", err)
process.exit(2)
})

View File

@@ -277,6 +277,8 @@ export type ToolUseContext = {
criticalSystemReminder_EXPERIMENTAL?: string criticalSystemReminder_EXPERIMENTAL?: string
/** Langfuse root trace span for this query turn. Passed down to tool execution for observability. */ /** Langfuse root trace span for this query turn. Passed down to tool execution for observability. */
langfuseTrace?: LangfuseSpan | null langfuseTrace?: LangfuseSpan | null
/** Langfuse root trace span for the outer/main agent trace. Used when subagents need to nest observations under the parent agent trace. */
langfuseRootTrace?: LangfuseSpan | null
/** Langfuse batch span wrapping a concurrent tool group. When set, tool observations are nested under it. */ /** Langfuse batch span wrapping a concurrent tool group. When set, tool observations are nested under it. */
langfuseBatchSpan?: LangfuseSpan | null langfuseBatchSpan?: LangfuseSpan | null
/** When true, preserve toolUseResult on messages even for subagents. /** When true, preserve toolUseResult on messages even for subagents.

View File

@@ -6,6 +6,7 @@
import { errorMessage } from '../../utils/errors.js' import { errorMessage } from '../../utils/errors.js'
import { import {
getMainLoopModel, getMainLoopModel,
getSmallFastModel,
parseUserSpecifiedModel, parseUserSpecifiedModel,
} from '../../utils/model/model.js' } from '../../utils/model/model.js'
import { import {
@@ -14,6 +15,7 @@ import {
getDefaultExternalAutoModeRules, getDefaultExternalAutoModeRules,
} from '../../utils/permissions/yoloClassifier.js' } from '../../utils/permissions/yoloClassifier.js'
import { getAutoModeConfig } from '../../utils/settings/settings.js' import { getAutoModeConfig } from '../../utils/settings/settings.js'
import { isPoorModeActive } from '../../commands/poor/poorMode.js'
import { sideQuery } from '../../utils/sideQuery.js' import { sideQuery } from '../../utils/sideQuery.js'
import { jsonStringify } from '../../utils/slowOperations.js' import { jsonStringify } from '../../utils/slowOperations.js'
@@ -90,6 +92,8 @@ export async function autoModeCritiqueHandler(options: {
const model = options.model const model = options.model
? parseUserSpecifiedModel(options.model) ? parseUserSpecifiedModel(options.model)
: isPoorModeActive()
? getSmallFastModel()
: getMainLoopModel() : getMainLoopModel()
const defaults = getDefaultExternalAutoModeRules() const defaults = getDefaultExternalAutoModeRules()

166
src/cli/updateCCB.ts Normal file
View File

@@ -0,0 +1,166 @@
/**
* `ccb update` — Check and install the latest version of claude-code-best.
*
* Detection strategy:
* 1. If `bun` is available and the current installation was done via bun → use `bun update -g`
* 2. Otherwise → use `npm install -g`
*/
import chalk from 'chalk'
import { execSync } from 'node:child_process'
import { existsSync, readFileSync } from 'node:fs'
import { homedir } from 'node:os'
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { logForDebugging } from '../utils/debug.js'
import { execFileNoThrowWithCwd } from '../utils/execFileNoThrow.js'
import { gracefulShutdown } from '../utils/gracefulShutdown.js'
import { writeToStdout } from '../utils/process.js'
const PACKAGE_NAME = 'claude-code-best'
function getCurrentVersion(): string {
// Read version from the nearest package.json (walks up from this file)
try {
const __dirname = dirname(fileURLToPath(import.meta.url))
// In dev: src/cli/updateCCB.ts → ../../package.json
// In build: dist/chunks/xxx.js → ../../package.json (may not exist)
const pkgPath = join(__dirname, '..', '..', 'package.json')
if (existsSync(pkgPath)) {
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))
if (pkg.version) return pkg.version
}
} catch {
// fallback
}
return MACRO.VERSION
}
function isCommandAvailable(cmd: string): boolean {
try {
execSync(`which ${cmd} 2>/dev/null`, { stdio: 'pipe' })
return true
} catch {
return false
}
}
/**
* Detect whether the current installation was done via bun.
* Checks if the binary path contains "bun" or if bun's global install dir has our package.
*/
function isBunInstallation(): boolean {
// Check if the running binary is under bun's global install path
const execPath = process.execPath
if (execPath.includes('bun')) {
return true
}
// Check bun's global install directory
const bunGlobalDir = join(homedir(), '.bun', 'install', 'global')
if (existsSync(join(bunGlobalDir, 'node_modules', PACKAGE_NAME))) {
return true
}
return false
}
/**
* Get the latest version from npm registry.
*/
async function getLatestVersion(): Promise<string | null> {
const result = await execFileNoThrowWithCwd(
'npm',
['view', `${PACKAGE_NAME}@latest`, 'version', '--prefer-online'],
{ abortSignal: AbortSignal.timeout(10_000), cwd: homedir() },
)
if (result.code !== 0) {
logForDebugging(`npm view failed: ${result.stderr}`)
return null
}
return result.stdout.trim()
}
/**
* Compare two semver strings. Returns true if a >= b.
*/
function gte(a: string, b: string): boolean {
const parseVer = (v: string) => v.replace(/^\D/, '').split('.').map(Number)
const pa = parseVer(a)
const pb = parseVer(b)
for (let i = 0; i < 3; i++) {
if ((pa[i] ?? 0) > (pb[i] ?? 0)) return true
if ((pa[i] ?? 0) < (pb[i] ?? 0)) return false
}
return true
}
export async function updateCCB(): Promise<void> {
const currentVersion = getCurrentVersion()
writeToStdout(`Current version: ${currentVersion}\n`)
// Determine package manager
const hasBun = isCommandAvailable('bun')
const useBun = isBunInstallation()
const pkgManager = useBun && hasBun ? 'bun' : 'npm'
writeToStdout(`Package manager: ${pkgManager}\n`)
writeToStdout('Checking for updates...\n')
// Get latest version
const latestVersion = await getLatestVersion()
if (!latestVersion) {
process.stderr.write(chalk.red('Failed to check for updates') + '\n')
process.stderr.write('Unable to fetch latest version from npm registry.\n')
await gracefulShutdown(1)
return
}
// Already up to date?
if (latestVersion === currentVersion || gte(currentVersion, latestVersion)) {
writeToStdout(chalk.green(`ccb is up to date (${currentVersion})`) + '\n')
await gracefulShutdown(0)
return
}
writeToStdout(
`New version available: ${latestVersion} (current: ${currentVersion})\n`,
)
writeToStdout(`Installing update via ${pkgManager}...\n`)
try {
if (pkgManager === 'bun') {
execSync(`bun update -g ${PACKAGE_NAME}`, {
stdio: 'inherit',
cwd: homedir(),
timeout: 120_000,
})
} else {
execSync(`npm install -g ${PACKAGE_NAME}@latest`, {
stdio: 'inherit',
cwd: homedir(),
timeout: 120_000,
})
}
writeToStdout(
chalk.green(
`Successfully updated from ${currentVersion} to ${latestVersion}`,
) + '\n',
)
} catch (error) {
process.stderr.write(chalk.red('Update failed') + '\n')
process.stderr.write(`${error}\n`)
process.stderr.write('\n')
process.stderr.write('Try manually updating with:\n')
if (pkgManager === 'bun') {
process.stderr.write(chalk.bold(` bun update -g ${PACKAGE_NAME}`) + '\n')
} else {
process.stderr.write(
chalk.bold(` npm install -g ${PACKAGE_NAME}@latest`) + '\n',
)
}
await gracefulShutdown(1)
}
await gracefulShutdown(0)
}

View File

@@ -14,6 +14,9 @@ import {
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS, type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
logEvent, logEvent,
} from '../../services/analytics/index.js' } from '../../services/analytics/index.js'
import { createTrace, endTrace, isLangfuseEnabled } from '../../services/langfuse/index.js'
import { getSessionId } from '../../bootstrap/state.js'
import { getAPIProvider } from '../../utils/model/providers.js'
import { jsonParse } from '../../utils/slowOperations.js' import { jsonParse } from '../../utils/slowOperations.js'
import { asSystemPrompt } from '../../utils/systemPromptType.js' import { asSystemPrompt } from '../../utils/systemPromptType.js'
@@ -146,6 +149,15 @@ export async function generateAgent(
? AGENT_CREATION_SYSTEM_PROMPT + AGENT_MEMORY_INSTRUCTIONS ? AGENT_CREATION_SYSTEM_PROMPT + AGENT_MEMORY_INSTRUCTIONS
: AGENT_CREATION_SYSTEM_PROMPT : AGENT_CREATION_SYSTEM_PROMPT
const langfuseTrace = isLangfuseEnabled()
? createTrace({
sessionId: getSessionId(),
model,
provider: getAPIProvider(),
name: 'agent-creation',
})
: null
const response = await queryModelWithoutStreaming({ const response = await queryModelWithoutStreaming({
messages: normalizeMessagesForAPI(messagesWithContext), messages: normalizeMessagesForAPI(messagesWithContext),
systemPrompt: asSystemPrompt([systemPrompt]), systemPrompt: asSystemPrompt([systemPrompt]),
@@ -161,9 +173,12 @@ export async function generateAgent(
hasAppendSystemPrompt: false, hasAppendSystemPrompt: false,
querySource: 'agent_creation', querySource: 'agent_creation',
mcpTools: [], mcpTools: [],
langfuseTrace,
}, },
}) })
endTrace(langfuseTrace)
const textBlocks = (Array.isArray(response.message.content) ? response.message.content : []).filter( const textBlocks = (Array.isArray(response.message.content) ? response.message.content : []).filter(
(block): block is ContentBlock & { type: 'text' } => block.type === 'text', (block): block is ContentBlock & { type: 'text' } => block.type === 'text',
) )

View File

@@ -6551,6 +6551,15 @@ async function run(): Promise<CommanderCommand> {
}, },
); );
// claude update — update ccb to the latest version via npm or bun
program
.command("update")
.description("Update claude-code-best (ccb) to the latest version")
.action(async () => {
const { updateCCB } = await import("./cli/updateCCB.js");
await updateCCB();
});
// ant-only commands // ant-only commands
if (process.env.USER_TYPE === "ant") { if (process.env.USER_TYPE === "ant") {
const validateLogId = (value: string) => { const validateLogId = (value: string) => {

View File

@@ -235,6 +235,9 @@ export async function* query(
// When called as a sub-agent, langfuseTrace is already set by runAgent() // When called as a sub-agent, langfuseTrace is already set by runAgent()
// — reuse it instead of creating an independent trace. // — reuse it instead of creating an independent trace.
const ownsTrace = !params.toolUseContext.langfuseTrace const ownsTrace = !params.toolUseContext.langfuseTrace
logForDebugging(
`[query] ownsTrace=${ownsTrace} incoming langfuseTrace=${params.toolUseContext.langfuseTrace ? 'present' : 'null/undefined'} isLangfuseEnabled=${isLangfuseEnabled()}`,
)
const langfuseTrace = params.toolUseContext.langfuseTrace const langfuseTrace = params.toolUseContext.langfuseTrace
?? (isLangfuseEnabled() ?? (isLangfuseEnabled()
? createTrace({ ? createTrace({

View File

@@ -10,6 +10,9 @@ import { getSmallFastModel } from '../utils/model/model.js'
import { asSystemPrompt } from '../utils/systemPromptType.js' import { asSystemPrompt } from '../utils/systemPromptType.js'
import { getResolvedLanguage } from '../utils/language.js' import { getResolvedLanguage } from '../utils/language.js'
import { queryModelWithoutStreaming } from './api/claude.js' import { queryModelWithoutStreaming } from './api/claude.js'
import { createTrace, endTrace, isLangfuseEnabled } from './langfuse/index.js'
import { getSessionId } from '../bootstrap/state.js'
import { getAPIProvider } from '../utils/model/providers.js'
import { getSessionMemoryContent } from './SessionMemory/sessionMemoryUtils.js' import { getSessionMemoryContent } from './SessionMemory/sessionMemoryUtils.js'
// Recap only needs recent context — truncate to avoid "prompt too long" on // Recap only needs recent context — truncate to avoid "prompt too long" on
@@ -42,6 +45,16 @@ export async function generateAwaySummary(
return null return null
} }
const model = getSmallFastModel()
const langfuseTrace = isLangfuseEnabled()
? createTrace({
sessionId: getSessionId(),
model,
provider: getAPIProvider(),
name: 'away-summary',
})
: null
try { try {
const memory = await getSessionMemoryContent() const memory = await getSessionMemoryContent()
const recent = messages.slice(-RECENT_MESSAGE_WINDOW) const recent = messages.slice(-RECENT_MESSAGE_WINDOW)
@@ -54,7 +67,7 @@ export async function generateAwaySummary(
signal, signal,
options: { options: {
getToolPermissionContext: async () => getEmptyToolPermissionContext(), getToolPermissionContext: async () => getEmptyToolPermissionContext(),
model: getSmallFastModel(), model,
toolChoice: undefined, toolChoice: undefined,
isNonInteractiveSession: false, isNonInteractiveSession: false,
hasAppendSystemPrompt: false, hasAppendSystemPrompt: false,
@@ -62,6 +75,7 @@ export async function generateAwaySummary(
querySource: 'away_summary', querySource: 'away_summary',
mcpTools: [], mcpTools: [],
skipCacheWrite: true, skipCacheWrite: true,
langfuseTrace,
}, },
}) })
@@ -69,14 +83,17 @@ export async function generateAwaySummary(
logForDebugging( logForDebugging(
`[awaySummary] API error: ${getAssistantMessageText(response)}`, `[awaySummary] API error: ${getAssistantMessageText(response)}`,
) )
endTrace(langfuseTrace, undefined, 'error')
return null return null
} }
endTrace(langfuseTrace)
return getAssistantMessageText(response) return getAssistantMessageText(response)
} catch (err) { } catch (err) {
if (err instanceof APIUserAbortError || signal.aborted) { if (err instanceof APIUserAbortError || signal.aborted) {
return null return null
} }
logForDebugging(`[awaySummary] generation failed: ${err}`) logForDebugging(`[awaySummary] generation failed: ${err}`)
endTrace(langfuseTrace, undefined, 'error')
return null return null
} }
} }

View File

@@ -1326,6 +1326,7 @@ async function streamCompactSummary({
agents: context.options.agentDefinitions.activeAgents, agents: context.options.agentDefinitions.activeAgents,
mcpTools: [], mcpTools: [],
effortValue: appState.effortValue, effortValue: appState.effortValue,
langfuseTrace: context.langfuseTrace,
}, },
}) })
const streamIter = streamingGen[Symbol.asyncIterator]() const streamIter = streamingGen[Symbol.asyncIterator]()

View File

@@ -25,6 +25,8 @@ import { jsonStringify } from '../utils/slowOperations.js'
import { isToolReferenceBlock } from '../utils/toolSearch.js' import { isToolReferenceBlock } from '../utils/toolSearch.js'
import { getAPIMetadata, getExtraBodyParams } from './api/claude.js' import { getAPIMetadata, getExtraBodyParams } from './api/claude.js'
import { getAnthropicClient } from './api/client.js' import { getAnthropicClient } from './api/client.js'
import { createTrace, endTrace, isLangfuseEnabled, recordLLMObservation } from './langfuse/index.js'
import { getSessionId } from '../bootstrap/state.js'
import { withTokenCountVCR } from './vcr.js' import { withTokenCountVCR } from './vcr.js'
// Minimal values for token counting with thinking enabled // Minimal values for token counting with thinking enabled
@@ -309,6 +311,15 @@ export async function countTokensViaHaikuFallback(
: betas : betas
// biome-ignore lint/plugin: token counting needs specialized parameters (thinking, betas) that sideQuery doesn't support // biome-ignore lint/plugin: token counting needs specialized parameters (thinking, betas) that sideQuery doesn't support
const apiStart = Date.now()
const langfuseTrace = isLangfuseEnabled()
? createTrace({
sessionId: getSessionId(),
model: normalizeModelStringForAPI(model),
provider: getAPIProvider(),
name: 'token-estimation',
})
: null
const response = await anthropic.beta.messages.create({ const response = await anthropic.beta.messages.create({
model: normalizeModelStringForAPI(model), model: normalizeModelStringForAPI(model),
max_tokens: containsThinking ? TOKEN_COUNT_MAX_TOKENS : 1, max_tokens: containsThinking ? TOKEN_COUNT_MAX_TOKENS : 1,
@@ -331,6 +342,22 @@ export async function countTokensViaHaikuFallback(
const cacheCreationTokens = usage.cache_creation_input_tokens || 0 const cacheCreationTokens = usage.cache_creation_input_tokens || 0
const cacheReadTokens = usage.cache_read_input_tokens || 0 const cacheReadTokens = usage.cache_read_input_tokens || 0
recordLLMObservation(langfuseTrace, {
model: normalizeModelStringForAPI(model),
provider: getAPIProvider(),
input: messagesToSend,
output: response.content,
usage: {
input_tokens: inputTokens,
output_tokens: usage.output_tokens,
cache_creation_input_tokens: cacheCreationTokens || undefined,
cache_read_input_tokens: cacheReadTokens || undefined,
},
startTime: new Date(apiStart),
endTime: new Date(),
})
endTrace(langfuseTrace)
return inputTokens + cacheCreationTokens + cacheReadTokens return inputTokens + cacheCreationTokens + cacheReadTokens
} }

View File

@@ -457,9 +457,14 @@ describe("buildClassifierUnavailableMessage", () => {
expect(msg).toContain("classifier-v1"); expect(msg).toContain("classifier-v1");
expect(msg).toContain("unavailable"); expect(msg).toContain("unavailable");
}); });
test("tells the model to wait and retry later", () => {
const msg = buildClassifierUnavailableMessage("Bash", "classifier-v1");
expect(msg).toContain("Wait briefly and then try this action again.");
expect(msg).toContain("come back to it later");
});
}); });
// ─── normalizeMessages ──────────────────────────────────────────────────
describe("normalizeMessages", () => { describe("normalizeMessages", () => {
test("splits multi-block assistant message into individual messages", () => { test("splits multi-block assistant message into individual messages", () => {

View File

@@ -374,6 +374,10 @@ export function createSubagentContext(
} }
return { return {
// Preserve the parent Langfuse trace separately so nested side queries
// like auto_mode can attach to the main agent trace instead of the
// subagent's own trace.
langfuseRootTrace: parentContext.langfuseTrace,
// Mutable state - cloned by default to maintain isolation // Mutable state - cloned by default to maintain isolation
// Clone overrides.readFileState if provided, otherwise clone from parent // Clone overrides.readFileState if provided, otherwise clone from parent
readFileState: cloneFileStateCache( readFileState: cloneFileStateCache(

View File

@@ -104,6 +104,7 @@ export function createApiQueryHook<TResult>(
querySource: config.name, querySource: config.name,
mcpTools: [], mcpTools: [],
agentId: context.toolUseContext.agentId, agentId: context.toolUseContext.agentId,
langfuseTrace: context.toolUseContext.langfuseTrace,
}, },
}) })

View File

@@ -84,6 +84,7 @@ Your response must be a JSON object matching one of the following schemas:
querySource: 'hook_prompt', querySource: 'hook_prompt',
mcpTools: [], mcpTools: [],
agentId: toolUseContext.agentId, agentId: toolUseContext.agentId,
langfuseTrace: toolUseContext.langfuseTrace,
outputFormat: { outputFormat: {
type: 'json_schema', type: 'json_schema',
schema: { schema: {

View File

@@ -7,6 +7,9 @@ import {
logEvent, logEvent,
} from '../../services/analytics/index.js' } from '../../services/analytics/index.js'
import { queryModelWithoutStreaming } from '../../services/api/claude.js' import { queryModelWithoutStreaming } from '../../services/api/claude.js'
import { createTrace, endTrace, isLangfuseEnabled } from '../../services/langfuse/index.js'
import { getSessionId } from '../../bootstrap/state.js'
import { getAPIProvider } from '../model/providers.js'
import { getEmptyToolPermissionContext } from '../../Tool.js' import { getEmptyToolPermissionContext } from '../../Tool.js'
import type { Message } from '../../types/message.js' import type { Message } from '../../types/message.js'
import { createAbortController } from '../abortController.js' import { createAbortController } from '../abortController.js'
@@ -209,6 +212,16 @@ export async function applySkillImprovement(
const updateList = updates.map(u => `- ${u.section}: ${u.change}`).join('\n') const updateList = updates.map(u => `- ${u.section}: ${u.change}`).join('\n')
const model = getSmallFastModel()
const langfuseTrace = isLangfuseEnabled()
? createTrace({
sessionId: getSessionId(),
model,
provider: getAPIProvider(),
name: 'skill-improvement-apply',
})
: null
const response = await queryModelWithoutStreaming({ const response = await queryModelWithoutStreaming({
messages: [ messages: [
createUserMessage({ createUserMessage({
@@ -238,7 +251,7 @@ Rules:
signal: createAbortController().signal, signal: createAbortController().signal,
options: { options: {
getToolPermissionContext: async () => getEmptyToolPermissionContext(), getToolPermissionContext: async () => getEmptyToolPermissionContext(),
model: getSmallFastModel(), model,
toolChoice: undefined, toolChoice: undefined,
isNonInteractiveSession: false, isNonInteractiveSession: false,
hasAppendSystemPrompt: false, hasAppendSystemPrompt: false,
@@ -246,9 +259,12 @@ Rules:
agents: [], agents: [],
querySource: 'skill_improvement_apply', querySource: 'skill_improvement_apply',
mcpTools: [], mcpTools: [],
langfuseTrace,
}, },
}) })
endTrace(langfuseTrace)
const responseText = extractTextContent(Array.isArray(response.message.content) ? response.message.content : []).trim() const responseText = extractTextContent(Array.isArray(response.message.content) ? response.message.content : []).trim()
const updatedContent = extractTag(responseText, 'updated_file') const updatedContent = extractTag(responseText, 'updated_file')

View File

@@ -0,0 +1,78 @@
import { describe, expect, test } from "bun:test";
import { isModelAlias } from "../aliases";
/**
* Replicate the guard used in getDefault*Model to verify it catches
* all alias forms that would cause recursion.
*/
function isAliasOrAliasWithSuffix(value: string): boolean {
const base = value.replace(/\[1m\]$/i, "").trim();
return isModelAlias(base);
}
describe("isAliasOrAliasWithSuffix", () => {
test("detects bare 'opus' alias", () => {
expect(isAliasOrAliasWithSuffix("opus")).toBe(true);
});
test("detects 'opus[1m]' alias", () => {
expect(isAliasOrAliasWithSuffix("opus[1m]")).toBe(true);
});
test("detects 'sonnet' alias", () => {
expect(isAliasOrAliasWithSuffix("sonnet")).toBe(true);
});
test("detects 'sonnet[1m]' alias", () => {
expect(isAliasOrAliasWithSuffix("sonnet[1m]")).toBe(true);
});
test("detects 'haiku' alias", () => {
expect(isAliasOrAliasWithSuffix("haiku")).toBe(true);
});
test("detects 'haiku[1m]' alias", () => {
expect(isAliasOrAliasWithSuffix("haiku[1m]")).toBe(true);
});
test("detects 'opusplan' alias", () => {
expect(isAliasOrAliasWithSuffix("opusplan")).toBe(true);
});
test("detects 'best' alias", () => {
expect(isAliasOrAliasWithSuffix("best")).toBe(true);
});
test("passes through concrete model IDs", () => {
expect(isAliasOrAliasWithSuffix("claude-opus-4-6")).toBe(false);
expect(isAliasOrAliasWithSuffix("claude-sonnet-4-6")).toBe(false);
expect(isAliasOrAliasWithSuffix("claude-haiku-4-5-20251001")).toBe(false);
});
test("passes through concrete model IDs with [1m] suffix", () => {
expect(isAliasOrAliasWithSuffix("claude-opus-4-6[1m]")).toBe(false);
expect(isAliasOrAliasWithSuffix("claude-sonnet-4-6[1m]")).toBe(false);
});
test("passes through 3P provider model IDs", () => {
expect(
isAliasOrAliasWithSuffix("us.anthropic.claude-opus-4-6-v1:0"),
).toBe(false);
expect(isAliasOrAliasWithSuffix("claude-opus-4-6@20251001")).toBe(false);
});
test("passes through arbitrary custom model names", () => {
expect(isAliasOrAliasWithSuffix("my-custom-model")).toBe(false);
expect(isAliasOrAliasWithSuffix("gpt-4o")).toBe(false);
});
test("handles whitespace around alias", () => {
expect(isAliasOrAliasWithSuffix(" opus ")).toBe(true);
expect(isAliasOrAliasWithSuffix(" opus[1m] ")).toBe(true);
});
test("handles case insensitivity of [1m] suffix", () => {
expect(isAliasOrAliasWithSuffix("opus[1M]")).toBe(true);
expect(isAliasOrAliasWithSuffix("sonnet[1M]")).toBe(true);
});
});

View File

@@ -28,6 +28,18 @@ import { getAPIProvider } from './providers.js'
import { LIGHTNING_BOLT } from '../../constants/figures.js' import { LIGHTNING_BOLT } from '../../constants/figures.js'
import { isModelAllowed } from './modelAllowlist.js' import { isModelAllowed } from './modelAllowlist.js'
import { type ModelAlias, isModelAlias } from './aliases.js' import { type ModelAlias, isModelAlias } from './aliases.js'
/**
* Returns true if the value is a model alias or a model alias with a suffix
* like [1m] (e.g. "opus", "opus[1m]", "sonnet", "haiku[1m]").
* Used to guard against infinite recursion when getDefault*Model() falls back
* to the user-specified setting — an alias like "opus[1m]" would cause
* parseUserSpecifiedModel → getDefaultOpusModel → parseUserSpecifiedModel loop.
*/
function isAliasOrAliasWithSuffix(value: string): boolean {
const base = value.replace(/\[1m\]$/i, '').trim()
return isModelAlias(base)
}
import { capitalize } from '../stringUtils.js' import { capitalize } from '../stringUtils.js'
export type ModelShortName = string export type ModelShortName = string
@@ -128,8 +140,10 @@ export function getDefaultOpusModel(): ModelName {
} }
// Fall back to user's configured model — custom providers may not // Fall back to user's configured model — custom providers may not
// recognize hardcoded Anthropic model IDs. // recognize hardcoded Anthropic model IDs.
// Skip if the user setting is a model alias (e.g. "opus", "opus[1m]") to
// avoid infinite recursion: parseUserSpecifiedModel(alias) → getDefaultOpusModel().
const userSpecifiedOpus = getUserSpecifiedModelSetting() const userSpecifiedOpus = getUserSpecifiedModelSetting()
if (userSpecifiedOpus) { if (userSpecifiedOpus && !isAliasOrAliasWithSuffix(userSpecifiedOpus)) {
return parseUserSpecifiedModel(userSpecifiedOpus) return parseUserSpecifiedModel(userSpecifiedOpus)
} }
// 3P providers (Bedrock, Vertex, Foundry) — kept as a separate branch // 3P providers (Bedrock, Vertex, Foundry) — kept as a separate branch
@@ -162,8 +176,9 @@ export function getDefaultSonnetModel(): ModelName {
// Fall back to user's configured model (ANTHROPIC_MODEL / settings) — // Fall back to user's configured model (ANTHROPIC_MODEL / settings) —
// custom providers (proxies, national clouds) may not recognize the // custom providers (proxies, national clouds) may not recognize the
// hardcoded Anthropic model IDs. // hardcoded Anthropic model IDs.
// Skip if the user setting is a model alias to avoid infinite recursion.
const userSpecified = getUserSpecifiedModelSetting() const userSpecified = getUserSpecifiedModelSetting()
if (userSpecified) { if (userSpecified && !isAliasOrAliasWithSuffix(userSpecified)) {
return parseUserSpecifiedModel(userSpecified) return parseUserSpecifiedModel(userSpecified)
} }
// Default to Sonnet 4.5 for 3P since they may not have 4.6 yet // Default to Sonnet 4.5 for 3P since they may not have 4.6 yet
@@ -190,8 +205,9 @@ export function getDefaultHaikuModel(): ModelName {
} }
// Fall back to user's configured model — custom providers may not // Fall back to user's configured model — custom providers may not
// recognize hardcoded Anthropic model IDs. // recognize hardcoded Anthropic model IDs.
// Skip if the user setting is a model alias to avoid infinite recursion.
const userSpecifiedHaiku = getUserSpecifiedModelSetting() const userSpecifiedHaiku = getUserSpecifiedModelSetting()
if (userSpecifiedHaiku) { if (userSpecifiedHaiku && !isAliasOrAliasWithSuffix(userSpecifiedHaiku)) {
return parseUserSpecifiedModel(userSpecifiedHaiku) return parseUserSpecifiedModel(userSpecifiedHaiku)
} }

View File

@@ -1,153 +1,136 @@
import { mock, describe, expect, test } from "bun:test"; import { mock, describe, expect, test } from 'bun:test'
import { createFileStateCacheWithSizeLimit } from '../../../utils/fileStateCache.js'
import { createSubagentContext } from '../../../utils/forkedAgent.js'
import { getEmptyToolPermissionContext } from '../../../Tool.js'
// Mock log.ts to cut the heavy dependency chain mock.module('src/utils/log.ts', () => ({
mock.module("src/utils/log.ts", () => ({
logError: () => {}, logError: () => {},
logToFile: () => {}, logToFile: () => {},
getLogDisplayTitle: () => "", getLogDisplayTitle: () => '',
logEvent: () => {}, logEvent: () => {},
logMCPError: () => {}, logMCPError: () => {},
logMCPDebug: () => {}, logMCPDebug: () => {},
dateToFilename: (d: Date) => d.toISOString().replace(/[:.]/g, "-"), dateToFilename: (d: Date) => d.toISOString().replace(/[:.]/g, '-'),
getLogFilePath: () => "/tmp/mock-log", getLogFilePath: () => '/tmp/mock-log',
attachErrorLogSink: () => {}, attachErrorLogSink: () => {},
getInMemoryErrors: () => [], getInMemoryErrors: () => [],
loadErrorLogs: async () => [], loadErrorLogs: async () => [],
getErrorLogByIndex: async () => null, getErrorLogByIndex: async () => null,
captureAPIRequest: () => {}, captureAPIRequest: () => {},
_resetErrorLogForTesting: () => {}, _resetErrorLogForTesting: () => {},
})); }))
const { const {
getDenyRuleForTool, getDenyRuleForTool,
getAskRuleForTool, getAskRuleForTool,
getDenyRuleForAgent, getDenyRuleForAgent,
filterDeniedAgents, filterDeniedAgents,
} = await import("../permissions"); } = await import('../permissions')
import { getEmptyToolPermissionContext } from "../../../Tool"; function makeContext(opts: { denyRules?: string[]; askRules?: string[] }) {
const ctx = getEmptyToolPermissionContext()
// ─── Helper ───────────────────────────────────────────────────────────── const deny: Record<string, string[]> = {}
const ask: Record<string, string[]> = {}
function makeContext(opts: { if (opts.denyRules?.length) deny.localSettings = opts.denyRules
denyRules?: string[]; if (opts.askRules?.length) ask.localSettings = opts.askRules
askRules?: string[]; return { ...ctx, alwaysDenyRules: deny, alwaysAskRules: ask } as any
}) {
const ctx = getEmptyToolPermissionContext();
const deny: Record<string, string[]> = {};
const ask: Record<string, string[]> = {};
// alwaysDenyRules stores raw rule strings — getDenyRules() calls
// permissionRuleValueFromString internally
if (opts.denyRules?.length) {
deny["localSettings"] = opts.denyRules;
}
if (opts.askRules?.length) {
ask["localSettings"] = opts.askRules;
}
return {
...ctx,
alwaysDenyRules: deny,
alwaysAskRules: ask,
} as any;
} }
function makeTool(name: string, mcpInfo?: { serverName: string; toolName: string }) { function makeTool(name: string, mcpInfo?: { serverName: string; toolName: string }) {
return { name, mcpInfo }; return { name, mcpInfo }
} }
// ─── getDenyRuleForTool ───────────────────────────────────────────────── describe('getDenyRuleForTool', () => {
test('returns null when no deny rules', () => {
const ctx = makeContext({})
expect(getDenyRuleForTool(ctx, makeTool('Bash'))).toBeNull()
})
test('returns matching deny rule for tool', () => {
const ctx = makeContext({ denyRules: ['Bash'] })
const result = getDenyRuleForTool(ctx, makeTool('Bash'))
expect(result).not.toBeNull()
expect(result!.ruleValue.toolName).toBe('Bash')
})
test('returns null for non-matching tool', () => {
const ctx = makeContext({ denyRules: ['Bash'] })
expect(getDenyRuleForTool(ctx, makeTool('Read'))).toBeNull()
})
test('rule with content does not match whole-tool deny', () => {
const ctx = makeContext({ denyRules: ['Bash(rm -rf)'] })
const result = getDenyRuleForTool(ctx, makeTool('Bash'))
expect(result).toBeNull()
})
})
describe("getDenyRuleForTool", () => { describe('getAskRuleForTool', () => {
test("returns null when no deny rules", () => { test('returns null when no ask rules', () => {
const ctx = makeContext({}); const ctx = makeContext({})
expect(getDenyRuleForTool(ctx, makeTool("Bash"))).toBeNull(); expect(getAskRuleForTool(ctx, makeTool('Bash'))).toBeNull()
}); })
test('returns matching ask rule', () => {
const ctx = makeContext({ askRules: ['Write'] })
const result = getAskRuleForTool(ctx, makeTool('Write'))
expect(result).not.toBeNull()
})
test('returns null for non-matching tool', () => {
const ctx = makeContext({ askRules: ['Write'] })
expect(getAskRuleForTool(ctx, makeTool('Bash'))).toBeNull()
})
})
test("returns matching deny rule for tool", () => { describe('getDenyRuleForAgent', () => {
const ctx = makeContext({ denyRules: ["Bash"] }); test('returns null when no deny rules', () => {
const result = getDenyRuleForTool(ctx, makeTool("Bash")); const ctx = makeContext({})
expect(result).not.toBeNull(); expect(getDenyRuleForAgent(ctx, 'Agent', 'Explore')).toBeNull()
expect(result!.ruleValue.toolName).toBe("Bash"); })
}); test('returns matching deny rule for agent type', () => {
const ctx = makeContext({ denyRules: ['Agent(Explore)'] })
const result = getDenyRuleForAgent(ctx, 'Agent', 'Explore')
expect(result).not.toBeNull()
})
test('returns null for non-matching agent type', () => {
const ctx = makeContext({ denyRules: ['Agent(Explore)'] })
expect(getDenyRuleForAgent(ctx, 'Agent', 'Research')).toBeNull()
})
})
test("returns null for non-matching tool", () => { describe('Langfuse trace propagation', () => {
const ctx = makeContext({ denyRules: ["Bash"] }); test('subagent context preserves parent trace for nested side queries', () => {
expect(getDenyRuleForTool(ctx, makeTool("Read"))).toBeNull(); const parentTrace = { id: 'parent-trace' } as never
}); const parentContext = {
...getEmptyToolPermissionContext(),
messages: [],
abortController: new AbortController(),
readFileState: createFileStateCacheWithSizeLimit(1),
getAppState: () => ({ toolPermissionContext: getEmptyToolPermissionContext() }),
setAppState: () => {},
updateFileHistoryState: () => {},
updateAttributionState: () => {},
setInProgressToolUseIDs: () => {},
setResponseLength: () => {},
langfuseTrace: parentTrace,
} as never
const subagentContext = createSubagentContext(parentContext)
expect(subagentContext.langfuseRootTrace).toBe(parentTrace)
})
})
test("rule with content does not match whole-tool deny", () => { describe('filterDeniedAgents', () => {
// getDenyRuleForTool uses toolMatchesRule which requires ruleContent === undefined test('returns all agents when no deny rules', () => {
// Rules like "Bash(rm -rf)" only match specific invocations, not the entire tool const ctx = makeContext({})
const ctx = makeContext({ denyRules: ["Bash(rm -rf)"] }); const agents = [{ agentType: 'Explore' }, { agentType: 'Research' }]
const result = getDenyRuleForTool(ctx, makeTool("Bash")); expect(filterDeniedAgents(agents, ctx, 'Agent')).toEqual(agents)
expect(result).toBeNull(); })
}); test('filters out denied agent type', () => {
}); const ctx = makeContext({ denyRules: ['Agent(Explore)'] })
const agents = [{ agentType: 'Explore' }, { agentType: 'Research' }]
// ─── getAskRuleForTool ────────────────────────────────────────────────── const result = filterDeniedAgents(agents, ctx, 'Agent')
expect(result).toHaveLength(1)
describe("getAskRuleForTool", () => { expect(result[0]!.agentType).toBe('Research')
test("returns null when no ask rules", () => { })
const ctx = makeContext({}); test('returns empty array when all agents denied', () => {
expect(getAskRuleForTool(ctx, makeTool("Bash"))).toBeNull(); const ctx = makeContext({ denyRules: ['Agent(Explore)', 'Agent(Research)'] })
}); const agents = [{ agentType: 'Explore' }, { agentType: 'Research' }]
expect(filterDeniedAgents(agents, ctx, 'Agent')).toEqual([])
test("returns matching ask rule", () => { })
const ctx = makeContext({ askRules: ["Write"] }); })
const result = getAskRuleForTool(ctx, makeTool("Write"));
expect(result).not.toBeNull();
});
test("returns null for non-matching tool", () => {
const ctx = makeContext({ askRules: ["Write"] });
expect(getAskRuleForTool(ctx, makeTool("Bash"))).toBeNull();
});
});
// ─── getDenyRuleForAgent ────────────────────────────────────────────────
describe("getDenyRuleForAgent", () => {
test("returns null when no deny rules", () => {
const ctx = makeContext({});
expect(getDenyRuleForAgent(ctx, "Agent", "Explore")).toBeNull();
});
test("returns matching deny rule for agent type", () => {
const ctx = makeContext({ denyRules: ["Agent(Explore)"] });
const result = getDenyRuleForAgent(ctx, "Agent", "Explore");
expect(result).not.toBeNull();
});
test("returns null for non-matching agent type", () => {
const ctx = makeContext({ denyRules: ["Agent(Explore)"] });
expect(getDenyRuleForAgent(ctx, "Agent", "Research")).toBeNull();
});
});
// ─── filterDeniedAgents ─────────────────────────────────────────────────
describe("filterDeniedAgents", () => {
test("returns all agents when no deny rules", () => {
const ctx = makeContext({});
const agents = [{ agentType: "Explore" }, { agentType: "Research" }];
expect(filterDeniedAgents(agents, ctx, "Agent")).toEqual(agents);
});
test("filters out denied agent type", () => {
const ctx = makeContext({ denyRules: ["Agent(Explore)"] });
const agents = [{ agentType: "Explore" }, { agentType: "Research" }];
const result = filterDeniedAgents(agents, ctx, "Agent");
expect(result).toHaveLength(1);
expect(result[0]!.agentType).toBe("Research");
});
test("returns empty array when all agents denied", () => {
const ctx = makeContext({
denyRules: ["Agent(Explore)", "Agent(Research)"],
});
const agents = [{ agentType: "Explore" }, { agentType: "Research" }];
expect(filterDeniedAgents(agents, ctx, "Agent")).toEqual([]);
});
});

View File

@@ -7,7 +7,8 @@ import { logForDebugging } from '../debug.js'
import { errorMessage } from '../errors.js' import { errorMessage } from '../errors.js'
import { lazySchema } from '../lazySchema.js' import { lazySchema } from '../lazySchema.js'
import { logError } from '../log.js' import { logError } from '../log.js'
import { getMainLoopModel } from '../model/model.js' import { getMainLoopModel, getSmallFastModel } from '../model/model.js'
import { isPoorModeActive } from '../../commands/poor/poorMode.js'
import { sideQuery } from '../sideQuery.js' import { sideQuery } from '../sideQuery.js'
import { jsonStringify } from '../slowOperations.js' import { jsonStringify } from '../slowOperations.js'
@@ -172,7 +173,7 @@ ${conversationContext ? `\nRecent conversation context:\n${conversationContext}`
Explain this command in context.` Explain this command in context.`
const model = getMainLoopModel() const model = isPoorModeActive() ? getSmallFastModel() : getMainLoopModel()
// Use sideQuery with forced tool choice for guaranteed structured output // Use sideQuery with forced tool choice for guaranteed structured output
const response = await sideQuery({ const response = await sideQuery({

View File

@@ -690,13 +690,16 @@ export const hasPermissionsToUseTool: CanUseToolFn = async (
setClassifierChecking(toolUseID) setClassifierChecking(toolUseID)
let classifierResult let classifierResult
try { try {
logForDebugging(
`[auto-mode] classifyYoloAction called with langfuseTrace=${context.langfuseTrace ? `id=${(context.langfuseTrace as unknown as Record<string, unknown>).id ?? 'present'}` : 'null/undefined'}`,
)
classifierResult = await classifyYoloAction( classifierResult = await classifyYoloAction(
context.messages, context.messages,
action, action,
context.options.tools, context.options.tools,
appState.toolPermissionContext, appState.toolPermissionContext,
context.abortController.signal, context.abortController.signal,
context.langfuseTrace, context.langfuseRootTrace ?? context.langfuseTrace,
) )
} finally { } finally {
clearClassifierChecking(toolUseID) clearClassifierChecking(toolUseID)
@@ -851,6 +854,7 @@ export const hasPermissionsToUseTool: CanUseToolFn = async (
CLASSIFIER_FAIL_CLOSED_REFRESH_MS, CLASSIFIER_FAIL_CLOSED_REFRESH_MS,
) )
) { ) {
if (appState.toolPermissionContext.shouldAvoidPermissionPrompts) {
logForDebugging( logForDebugging(
'Auto mode classifier unavailable, denying with retry guidance (fail closed)', 'Auto mode classifier unavailable, denying with retry guidance (fail closed)',
{ level: 'warn' }, { level: 'warn' },
@@ -868,6 +872,23 @@ export const hasPermissionsToUseTool: CanUseToolFn = async (
), ),
} }
} }
logForDebugging(
'Auto mode classifier unavailable, falling back to prompting with retry guidance (fail closed)',
{ level: 'warn' },
)
return {
behavior: 'ask',
decisionReason: {
type: 'classifier',
classifier: 'auto-mode',
reason: 'Classifier unavailable',
},
message: buildClassifierUnavailableMessage(
tool.name,
classifierResult.model,
),
}
}
// Fail open: fall back to normal permission handling // Fail open: fall back to normal permission handling
logForDebugging( logForDebugging(
'Auto mode classifier unavailable, falling back to normal permission handling (fail open)', 'Auto mode classifier unavailable, falling back to normal permission handling (fail open)',

View File

@@ -28,7 +28,8 @@ import { errorMessage } from '../errors.js'
import { lazySchema } from '../lazySchema.js' import { lazySchema } from '../lazySchema.js'
import { extractTextContent } from '../messages.js' import { extractTextContent } from '../messages.js'
import { resolveAntModel } from '../model/antModels.js' import { resolveAntModel } from '../model/antModels.js'
import { getMainLoopModel } from '../model/model.js' import { getDefaultSonnetModel, getMainLoopModel } from '../model/model.js'
import { isPoorModeActive } from '../../commands/poor/poorMode.js'
import { getAutoModeConfig } from '../settings/settings.js' import { getAutoModeConfig } from '../settings/settings.js'
import { sideQuery } from '../sideQuery.js' import { sideQuery } from '../sideQuery.js'
import type { LangfuseSpan } from '../../services/langfuse/index.js' import type { LangfuseSpan } from '../../services/langfuse/index.js'
@@ -1350,6 +1351,10 @@ function getClassifierModel(): string {
if (config?.model) { if (config?.model) {
return config.model return config.model
} }
// Poor mode: downgrade classifier to Sonnet to reduce cost
if (isPoorModeActive()) {
return getDefaultSonnetModel()
}
return getMainLoopModel() return getMainLoopModel()
} }

View File

@@ -19,6 +19,7 @@ import { createTrace, createChildSpan, endTrace, recordLLMObservation } from '..
import type { LangfuseSpan } from '../services/langfuse/index.js' import type { LangfuseSpan } from '../services/langfuse/index.js'
import { convertMessagesToLangfuse, convertOutputToLangfuse, convertToolsToLangfuse } from '../services/langfuse/convert.js' import { convertMessagesToLangfuse, convertOutputToLangfuse, convertToolsToLangfuse } from '../services/langfuse/convert.js'
import { getModelBetas, modelSupportsStructuredOutputs } from './betas.js' import { getModelBetas, modelSupportsStructuredOutputs } from './betas.js'
import { logForDebugging } from './debug.js'
import { errorMessage } from './errors.js' import { errorMessage } from './errors.js'
import { computeFingerprint } from './fingerprint.js' import { computeFingerprint } from './fingerprint.js'
import { getAPIProvider } from './model/providers.js' import { getAPIProvider } from './model/providers.js'
@@ -194,14 +195,28 @@ export async function sideQuery(opts: SideQueryOptions): Promise<BetaMessage> {
// When parentSpan is provided, create a child span nested under the // When parentSpan is provided, create a child span nested under the
// main agent trace; otherwise create a standalone root trace. // main agent trace; otherwise create a standalone root trace.
const langfuseTrace = opts.parentSpan const _ps = opts.parentSpan
? createChildSpan(opts.parentSpan, { // eslint-disable-next-line no-constant-condition
if (opts.querySource === 'auto_mode') {
logForDebugging(
`[sideQuery] auto_mode parentSpan=${_ps ? `id=${(_ps as unknown as Record<string, unknown>).id ?? 'present'}` : 'null/undefined'} querySource=${opts.querySource}`,
)
}
// When parentSpan is provided, create a child span nested under the
// main agent trace. For auto_mode queries, we must always nest under
// a parent span — never create a standalone root trace (agent type),
// as auto_mode observations should appear as spans within the parent.
// For other query sources without a parent, create a standalone trace.
const langfuseTrace = _ps
? createChildSpan(_ps, {
name: traceName, name: traceName,
sessionId: getSessionId(), sessionId: getSessionId(),
model: normalizedModel, model: normalizedModel,
provider, provider,
querySource: opts.querySource, querySource: opts.querySource,
}) })
: opts.querySource === 'auto_mode'
? null
: createTrace({ : createTrace({
sessionId: getSessionId(), sessionId: getSessionId(),
model: normalizedModel, model: normalizedModel,

View File

@@ -64,15 +64,6 @@ export default defineConfig({
chunkFileNames: "chunks/[name]-[hash].js", chunkFileNames: "chunks/[name]-[hash].js",
}, },
// Externalize native addon packages (they contain .node binaries)
external: [
/audio-capture-napi/,
/color-diff-napi/,
/image-processor-napi/,
/modifiers-napi/,
/url-handler-napi/,
],
plugins: [ plugins: [
rawAssetPlugin([".md", ".txt", ".html", ".css"]), rawAssetPlugin([".md", ".txt", ".html", ".css"]),
featureFlagsPlugin(), featureFlagsPlugin(),