diff --git a/CHANGELOG.md b/CHANGELOG.md index 67718f9..e0d74ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ This project follows the [Keep a Changelog](https://keepachangelog.com/) format. +## [Unreleased] + +### Added + +- **Quote reconstruction for newer WeChat clients:** Losslessly parse message IDs and resolve ID-only `svr_id` text and partial quotes through a per-account, per-conversation SQLite side store. Images, video, voice, and attachments are written directly into plugin-owned OpenClaw managed storage, using one retained file with time, count, byte-budget, and single-file eviction limits. Restored attachments include tool-access hints so agents can locate and read the file when automatic extraction fails. +- **Compatible degradation:** Disable quote caching when `node:sqlite` is unavailable or `quoteCache.enabled=false`, with no in-memory fallback. Cache failures never interrupt normal message delivery. + ## [2.4.7] - 2026-08-31 ### Fixed diff --git a/CHANGELOG.zh_CN.md b/CHANGELOG.zh_CN.md index c052898..6a65b6d 100644 --- a/CHANGELOG.zh_CN.md +++ b/CHANGELOG.zh_CN.md @@ -4,6 +4,13 @@ 本项目遵循 [Keep a Changelog](https://keepachangelog.com/) 格式。 +## [未发布] + +### 新增 + +- **新版微信引用消息还原:** 对消息 ID 做无损解析,并用按账号、会话隔离的 SQLite 旁路存储还原只携带 `svr_id` 的文本引用和局部引用。图片、视频、语音及附件首次直接写入插件专属的 OpenClaw 受管目录,以单份文件支持按时间、条数、空间和单文件大小淘汰;还原引用附件时会提供工具访问提示,便于 agent 在自动抽取失败后定位并读取文件。 +- **兼容降级:** `node:sqlite` 不可用或 `quoteCache.enabled=false` 时关闭引用缓存,不启用内存替代方案;缓存异常不会影响正常消息收发。 + ## [2.4.7] - 2026-08-31 ### 修复 diff --git a/README.md b/README.md index 1d80d95..d34065d 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ OpenClaw's Weixin channel plugin. Connect an OpenClaw Gateway to Weixin with QR- | Component | Requirement | | --- | --- | -| Node.js | `>=22` | +| Node.js | `>=22.13.0` | | OpenClaw runtime check | `>=2026.3.22` | | npm peer dependency | `>=2026.5.12` | @@ -100,6 +100,39 @@ Set an optional identifier for backend log attribution and monitoring: `botAgent` is used for observability only. It is not an authentication credential and does not control message routing. +**Format** (UA-style): + +- One or more `Name/Version` tokens, space-separated +- Each token may optionally be followed by ` (comment)` +- ASCII only; total length ≤ 256 bytes +- Invalid tokens are silently dropped during sanitization; falls back to + `OpenClaw` if nothing valid remains + +Examples that pass through unchanged: + +- `MyBot/1.2.0` +- `MyBot/1.2.0 (region=cn;env=prod)` +- `MyBot/1.2.0 LangChain/0.3.5` +- `MyBot/1.2.0-rc.1+build.5` + +**Note**: `bot_agent` is for observability only — it is not used for +authentication or routing. All registered agents on this plugin instance +currently share the same `botAgent` declaration; per-agent overrides may be +added in a future version if needed. + +## Local quote cache + +Newer WeChat clients may send only a server message ID for a quoted message. The plugin +stores the required text and media metadata locally so later quotes can restore their +context. The cache is enabled by default and failures do not interrupt normal message +delivery. + +Configure it under `channels.openclaw-weixin.quoteCache` when you need different +retention or size limits. The default limits are 30 days and 10,000 text records per +account, plus 7 days, 256 MiB per account, and 25 MiB per media file. See the +[local quote cache guide](./docs/quote-cache_zh_CN.md) for the complete configuration, +storage behavior, and validation details. + ## Uninstall ```bash @@ -135,6 +168,7 @@ If the problem persists, inspect the Gateway log and verify that the account has | --- | --- | | Backend integration | [Weixin backend API protocol](./docs/protocol.md) | | CI and local quality checks | [CI guide](./docs/ci.md) | +| Development and local validation | [Development guide](./docs/development.md) | | OpenClaw channel configuration | [OpenClaw channels](https://docs.openclaw.ai/channels) | | Release history | [CHANGELOG.md](./CHANGELOG.md) | @@ -142,10 +176,10 @@ The backend protocol document is intended for developers implementing or integra ## Development -This repository uses npm and requires Node.js `>=22`. +This repository uses npm and requires Node.js `>=22.13.0`. ```bash -npm ci --ignore-scripts +npm ci --ignore-scripts --include=dev npm run ci ``` @@ -157,6 +191,8 @@ npm run test:coverage Pull requests run the same quality, unit-test, coverage, build, and package smoke checks in GitHub Actions. See the [CI guide](./docs/ci.md) for details. +See the [development guide](./docs/development.md) for the complete worktree, dependency, packaging, and local installation workflow. + ## Contributing Bug reports, documentation improvements, tests, and code contributions are welcome. Please keep pull requests focused and include validation details. For changes to the backend integration, update the [protocol documentation](./docs/protocol.md) together with the implementation. diff --git a/README.zh_CN.md b/README.zh_CN.md index b08855c..82a1530 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -21,7 +21,7 @@ OpenClaw 的微信渠道插件。通过扫码登录将 OpenClaw Gateway 连接 | 组件 | 要求 | | --- | --- | -| Node.js | `>=22` | +| Node.js | `>=22.13.0` | | OpenClaw 运行时检查 | `>=2026.3.22` | | npm peer dependency | `>=2026.5.12` | @@ -100,6 +100,33 @@ openclaw config set session.dmScope per-account-channel-peer `botAgent` 仅用于观测,不是鉴权凭证,也不控制消息路由。 +**格式规范**(UA 风格): + +- 一个或多个 `Name/Version` token,空格分隔 +- 每个 token 可选地跟一个 ` (comment)` +- 仅允许 ASCII 字符;总长 ≤ 256 字节 +- 不合规的 token 在清洗时静默丢弃;如果最终为空,回退到 `OpenClaw` + +可直接使用的示例: + +- `MyBot/1.2.0` +- `MyBot/1.2.0 (region=cn;env=prod)` +- `MyBot/1.2.0 LangChain/0.3.5` +- `MyBot/1.2.0-rc.1+build.5` + +**注意**:`bot_agent` 仅用于观测,**不参与鉴权或路由**。当前本插件实例下所有 +已注册的 agent 共享同一个 `botAgent` 声明;如有需要按 agent 单独标识的场景, +可在后续版本扩展配置。 + +## 引用消息本地缓存 + +新版微信客户端可能只在引用消息中提供服务端消息 ID。插件会在本地保存必要的文本和媒体元数据, +以便后续引用消息还原上下文。缓存默认开启,缓存故障不会中断正常消息收发。 + +如需调整保留时间或空间限制,可配置 `channels.openclaw-weixin.quoteCache`。默认文本缓存保留 30 天、 +每个账号最多 10,000 条;媒体缓存保留 7 天、每个账号最多 256 MiB、单个文件最多 25 MiB。 +完整配置、存储行为和验证说明见[引用消息本地缓存开发说明](./docs/quote-cache_zh_CN.md)。 + ## 卸载 ```bash @@ -135,6 +162,7 @@ openclaw gateway restart | --- | --- | | 后端对接 | [微信后端 API 协议](./docs/protocol_zh_CN.md) | | CI 和本地质量检查 | [CI 指南](./docs/ci_zh_CN.md) | +| 开发与本地验证 | [开发者指南](./docs/development_zh_CN.md) | | OpenClaw 渠道配置 | [OpenClaw Channels](https://docs.openclaw.ai/channels) | | 发布历史 | [CHANGELOG.zh_CN.md](./CHANGELOG.zh_CN.md) | @@ -142,7 +170,7 @@ openclaw gateway restart ## 开发 -本项目使用 npm,并要求 Node.js `>=22`。 +本项目使用 npm,并要求 Node.js `>=22.13.0`。 ```bash npm ci --ignore-scripts @@ -157,6 +185,8 @@ npm run test:coverage Pull Request 会在 GitHub Actions 中执行质量检查、单元测试、覆盖率、构建和 npm 包冒烟测试。详细说明见 [CI 指南](./docs/ci_zh_CN.md)。 +从 worktree 创建、依赖安装到本地打包和插件安装的完整流程见[开发者指南](./docs/development_zh_CN.md)。 + ## 参与贡献 欢迎提交问题、改进文档、补充测试和贡献代码。请保持 Pull Request 聚焦,并附上验证结果。修改后端集成时,请同步更新[协议文档](./docs/protocol_zh_CN.md)。 diff --git a/docs/ci.md b/docs/ci.md index 55aa0d2..ccb10fe 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -4,7 +4,7 @@ This document describes the local quality checks and GitHub Actions workflow for ## Local checks -The project requires Node.js `>=22`. After cloning the repository or changing dependencies, install the locked dependencies first: +The project requires Node.js `>=22.13.0`. After cloning the repository or changing dependencies, install the locked dependencies first: ```bash npm ci --ignore-scripts diff --git a/docs/ci_zh_CN.md b/docs/ci_zh_CN.md index 12edf5e..05024df 100644 --- a/docs/ci_zh_CN.md +++ b/docs/ci_zh_CN.md @@ -4,7 +4,7 @@ ## 本地检查 -项目要求 Node.js `>=22`。首次获取代码或依赖发生变化后,先安装 lockfile 中锁定的依赖: +项目要求 Node.js `>=22.13.0`。首次获取代码或依赖发生变化后,先安装 lockfile 中锁定的依赖: ```bash npm ci --ignore-scripts diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..b2b086c --- /dev/null +++ b/docs/development.md @@ -0,0 +1,160 @@ +# Development and Local Validation + +This guide describes the common workflow for developing, testing, and locally validating this project. + +## Prerequisites + +Make sure Node.js, npm, Git, and OpenClaw are installed: + +```bash +node --version +npm --version +git --version +openclaw --version +``` + +The required Node.js version is defined by the `engines` field in `package.json`. + +## Create a worktree + +Use a separate worktree for an independent feature or pull request: + +```bash +PR_NUMBER=123 # replace with the actual pull request number +WORKTREE_DIR="/tmp/openclaw-weixin-pr-${PR_NUMBER}" +REVIEW_BRANCH="review/pr-${PR_NUMBER}" + +git fetch origin main +git fetch origin "+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/pr-${PR_NUMBER}" +git worktree add -b "$REVIEW_BRANCH" "$WORKTREE_DIR" origin/main +cd "$WORKTREE_DIR" +git merge --no-ff "origin/pr-${PR_NUMBER}" +``` + +Check the current worktree and branch: + +```bash +git branch --show-current +git status +``` + +## Resolve merge conflicts + +List conflicted files: + +```bash +git status +git diff --name-only --diff-filter=U +``` + +Edit the files, keep the correct content, and remove the `<<<<<<<`, `=======`, and `>>>>>>>` markers. Then finish the merge: + +```bash +git add +git commit -m "resolve merge conflicts" +git diff --check +``` + +To synchronize with a newer main branch: + +```bash +git fetch origin main +git merge origin/main +``` + +## Install dependencies + +Run the command from the project root, where `package.json` and `package-lock.json` are located: + +```bash +npm ci --ignore-scripts --include=dev +``` + +`npm ci` installs the versions recorded in the lockfile and is suitable for clean, reproducible validation. + +When changing dependencies, use `npm install`, commit both dependency files, and run `npm ci` again: + +```bash +npm install --save-dev --save-exact @ +npm ci --ignore-scripts --include=dev +``` + +Installation warnings do not necessarily mean that installation failed. Check the command exit code and final result. Do not run `npm audit fix --force` without reviewing the changes it would make. + +## Run quality checks + +Run the complete check: + +```bash +npm run ci +``` + +This runs formatting, linting, type checking, unit tests, and the build. To run them separately: + +```bash +npm run format:check +npm run lint +npm run typecheck +npm run test:unit +npm run build +``` + +Run coverage separately when needed: + +```bash +npm run test:coverage +``` + +## Pack the local plugin + +Build from the project root, then create a local npm package: + +```bash +npm run build + +PACKAGE_DIR=$(mktemp -d /tmp/openclaw-weixin-package.XXXXXX) +npm pack --pack-destination "$PACKAGE_DIR" + +PACKAGE_TGZ=$(find "$PACKAGE_DIR" \ + -maxdepth 1 \ + -type f \ + -name '*.tgz' \ + -print \ + -quit) + +echo "$PACKAGE_TGZ" +test -n "$PACKAGE_TGZ" || { echo "Package not found"; exit 1; } +``` + +`PACKAGE_DIR` is the temporary directory. `PACKAGE_TGZ` is the `.tgz` file generated inside it and must be passed to the installer. + +## Install and validate the local package + +```bash +openclaw plugins install "$PACKAGE_TGZ" \ + --force \ + --accept-capabilities + +openclaw gateway restart +openclaw channels status +``` + +Perform manual checks relevant to the change, such as login, message delivery, media handling, configuration, restart behavior, and failure fallback. + +To avoid changing an existing OpenClaw configuration, use a separate `OPENCLAW_STATE_DIR` during validation. + +## Common issues + +- `uv_cwd` or `process.cwd`: the current directory was deleted, often because the shell was inside `dist` while the build cleaned it. Change back to the project root. +- `Plugin install source must not be empty`: `PACKAGE_TGZ` is unset or empty. Run the packaging commands again. +- `HOOK.md missing`: the temporary `PACKAGE_DIR` directory was passed to the installer instead of the `PACKAGE_TGZ` archive. + +## Before committing + +```bash +git status +git diff --check +npm run ci +``` + +Review the code, tests, and documentation before committing. Use the repository's established release process for versioning and publish packages separately after the change is merged. diff --git a/docs/development_zh_CN.md b/docs/development_zh_CN.md new file mode 100644 index 0000000..0fa09c2 --- /dev/null +++ b/docs/development_zh_CN.md @@ -0,0 +1,152 @@ +# 开发与本地验证 + +本文说明本项目常用的开发、测试和本地插件验证流程。 + +## 环境准备 + +确认 Node.js、npm、Git 和 OpenClaw 已安装: + +```bash +node --version +npm --version +git --version +openclaw --version +``` + +Node.js 版本要求以 `package.json` 的 `engines` 配置为准。 + +## 创建 worktree + +为独立功能或 PR 创建 worktree,避免影响当前工作目录: + +```bash +PR_NUMBER=123 # replace with the actual PR number +WORKTREE_DIR="/tmp/openclaw-weixin-pr-${PR_NUMBER}" +REVIEW_BRANCH="review/pr-${PR_NUMBER}" + +git fetch origin main +git fetch origin "+refs/pull/${PR_NUMBER}/head:refs/remotes/origin/pr-${PR_NUMBER}" +git worktree add -b "$REVIEW_BRANCH" "$WORKTREE_DIR" origin/main +cd "$WORKTREE_DIR" +git merge --no-ff "origin/pr-${PR_NUMBER}" +``` + +确认状态: + +```bash +git branch --show-current +git status +``` + +## 处理合并冲突 + +查看冲突文件: + +```bash +git status +git diff --name-only --diff-filter=U +``` + +编辑冲突文件,保留正确内容并删除 `<<<<<<<`、`=======`、`>>>>>>>` 标记,然后执行: + +```bash +git add <已解决的文件> +git commit -m "resolve merge conflicts" +git diff --check +``` + +如果主分支有更新,可以重新同步: + +```bash +git fetch origin main +git merge origin/main +``` + +## 安装依赖 + +在包含 `package.json` 和 `package-lock.json` 的项目根目录执行: + +```bash +npm ci --ignore-scripts --include=dev +``` + +`npm ci` 按锁文件安装依赖,适合干净、可复现的测试环境。 + +修改依赖时使用 `npm install`,完成后提交更新后的 `package.json` 和 `package-lock.json`,再重新执行 `npm ci` 验证: + +```bash +npm install --save-dev --save-exact @ +npm ci --ignore-scripts --include=dev +``` + +安装警告不一定表示失败,应以命令退出码和最终结果为准。不要未经确认直接执行 `npm audit fix --force`。 + +## 执行质量检查 + +```bash +npm run ci +``` + +该命令会依次执行格式检查、Lint、类型检查、单元测试和构建。需要单独执行时: + +```bash +npm run format:check +npm run lint +npm run typecheck +npm run test:unit +npm run build +``` + +## 打包本地插件 + +先在项目根目录完成构建,然后使用 `npm pack` 生成本地安装包: + +```bash +npm run build + +PACKAGE_DIR=$(mktemp -d /tmp/openclaw-weixin-package.XXXXXX) +npm pack --pack-destination "$PACKAGE_DIR" + +PACKAGE_TGZ=$(find "$PACKAGE_DIR" \ + -maxdepth 1 \ + -type f \ + -name '*.tgz' \ + -print \ + -quit) + +echo "$PACKAGE_TGZ" +test -n "$PACKAGE_TGZ" || { echo "找不到安装包"; exit 1; } +``` + +`PACKAGE_DIR` 是临时目录,`PACKAGE_TGZ` 是其中生成的 `.tgz` 文件。安装时必须使用后者。 + +## 安装并验证本地插件 + +```bash +openclaw plugins install "$PACKAGE_TGZ" \ + --force \ + --accept-capabilities + +openclaw gateway restart +openclaw channels status +``` + +根据本次修改内容完成手工验证,例如消息收发、登录、媒体、配置、重启后状态和异常降级行为。 + +如不希望影响现有 OpenClaw 配置,可以在验证前使用独立的 `OPENCLAW_STATE_DIR`。 + +## 常见问题 + +- `uv_cwd` 或 `process.cwd`:当前目录已被删除,通常是停留在 `dist` 中执行构建;切回项目根目录。 +- `Plugin install source must not be empty`:`PACKAGE_TGZ` 未设置或为空,重新执行打包流程。 +- `HOOK.md missing`:把 `PACKAGE_DIR` 目录传给了安装器,应传入 `PACKAGE_TGZ` 文件。 + +## 提交前检查 + +```bash +git status +git diff --check +npm run ci +``` + +确认代码、测试和文档无误后再提交。版本发布应使用项目既有的版本发布流程,并在合并后单独进行。 diff --git a/docs/quote-cache_zh_CN.md b/docs/quote-cache_zh_CN.md new file mode 100644 index 0000000..e016273 --- /dev/null +++ b/docs/quote-cache_zh_CN.md @@ -0,0 +1,92 @@ +# 引用消息本地缓存 + +本文说明引用消息本地缓存的设计、配置和验证方式。普通用户只需要关注 +README 中的配置入口;本文面向需要排查行为、维护代码或验证发布包的开发者。 + +## 功能目的 + +新版微信客户端可能只在引用消息中提供服务端消息 ID(`svr_id`),而不再携带 +被引用消息的正文或媒体内容。插件使用按账号、会话隔离的 SQLite 旁路存储, +在后续引用到来时还原可用的文本、媒体元数据和附件访问信息。 + +缓存默认开启,正常消息投递不依赖缓存是否命中。 + +## 配置 + +配置路径为 `channels.openclaw-weixin.quoteCache`: + +| 配置项 | 默认值 | 说明 | +| --- | ---: | --- | +| `enabled` | `true` | 是否启用本地引用消息还原。 | +| `retentionDays` | `30` | 文本及消息元数据的保留天数。 | +| `maxMessagesPerAccount` | `10000` | 每个账号最多保留的消息记录数。 | +| `mediaRetentionDays` | `7` | 引用媒体文件的保留天数。 | +| `maxMediaBytesPerAccount` | `268435456` | 每个账号最多保留的媒体总大小,单位为字节(256 MiB)。 | +| `maxSingleMediaBytes` | `26214400` | 单个可保留媒体文件的最大大小,单位为字节(25 MiB)。 | + +示例: + +```json +{ + "channels": { + "openclaw-weixin": { + "quoteCache": { + "enabled": true, + "retentionDays": 14, + "maxMessagesPerAccount": 5000, + "mediaRetentionDays": 3, + "maxMediaBytesPerAccount": 134217728, + "maxSingleMediaBytes": 26214400 + } + } + } +} +``` + +修改配置后重启 Gateway: + +```bash +openclaw gateway restart +``` + +## 数据和媒体生命周期 + +- 入站和出站引用元数据按账号和会话隔离,避免不同账号或会话之间串数据。 +- 图片、视频、语音和附件写入插件专属的 OpenClaw 受管目录;当前消息和后续引用复用同一份文件。 +- 还原附件时提供原文件名、受管源路径以及工作区 `media/inbound/` 提示,便于 file/PDF 工具访问。 +- 启动时、每小时、每写入 100 条记录、媒体空间超限时执行清理;过期记录命中查询时也会惰性清理。 +- 超过保留时间、账号记录数量、账号媒体空间或单文件大小限制时,按限制淘汰旧数据或跳过媒体保留。 +- 删除账号时同步删除该账号的引用记录和保留媒体。 +- 早于缓存初始化的历史消息无法还原,会返回明确的缓存未命中占位信息。 + +## 兼容性和降级 + +- 项目要求 Node.js `>=22.13.0`,此版本开始 `node:sqlite` 无需使用实验性启动参数。 +- 消息 ID 以字符串形式处理,避免超过 JavaScript 安全整数范围时发生精度丢失。 +- 部分引用会进行必要的 MD5 校验;校验失败时不会伪造引用内容。 +- 当前 Node.js 不提供 `node:sqlite`,或数据库无法打开时,插件记录警告并关闭引用缓存。 +- 缓存关闭或不可用时不使用内存缓存替代,缓存故障也不会中断正常消息收发。 + +## 开发验证 + +重点单元测试: + +```bash +npx vitest run --coverage=false src/messaging/quote-store.test.ts src/messaging/partial-quote.test.ts +``` + +完整质量检查: + +```bash +npm ci --ignore-scripts +npm run ci +npm run test:coverage +``` + +手工验证至少覆盖以下场景: + +1. 发送文本后,用只携带 `svr_id` 的引用消息进行引用,Agent 能看到原文。 +2. 引用图片、视频、语音和文件,Agent 能获得对应媒体信息和可访问路径。 +3. 重启 Gateway 后再次引用,已缓存消息仍可还原。 +4. 多账号、多会话之间不存在引用数据串线。 +5. 缓存关闭、SQLite 不可用和媒体超过大小限制时,普通消息仍能正常收发。 diff --git a/package-lock.json b/package-lock.json index 46122b2..22839aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,11 +10,11 @@ "license": "MIT", "dependencies": { "qrcode-terminal": "0.12.0", - "zod": "4.4.3" + "zod": "^4.3.6" }, "devDependencies": { "@vitest/coverage-v8": "^3.1.0", - "openclaw": "2026.5.12", + "openclaw": "2026.8.1", "oxfmt": "0.60.0", "oxlint": "1.80.0", "silk-wasm": "^3.7.1", @@ -22,16 +22,16 @@ "vitest": "^3.1.0" }, "engines": { - "node": ">=22" + "node": ">=22.13.0" }, "peerDependencies": { "openclaw": ">=2026.5.12" } }, "node_modules/@agentclientprotocol/sdk": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/@agentclientprotocol/sdk/-/sdk-0.21.0.tgz", - "integrity": "sha512-ONj+Q8qOdNQp5XbH5jnMwzT9IKZJsSN0p0lkceS4GtUtNOPVLpNzSS8gqQdGMKfBvA0ESbkL8BTaSN1Rc9miEw==", + "version": "1.4.0", + "resolved": "https://mirrors.tencent.com/npm/@agentclientprotocol/sdk/-/sdk-1.4.0.tgz", + "integrity": "sha512-/eufudw+aFY1LKLolT6yFE6UMmYRl7fMJ/DEONSIyR6wI3slHWITBsANRGqXEY8FRzqUxwh7QEaGiZHcJPVThg==", "dev": true, "license": "Apache-2.0", "peerDependencies": { @@ -52,841 +52,298 @@ "node": ">=6.0.0" } }, - "node_modules/@anthropic-ai/sdk": { - "version": "0.91.1", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", - "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", - "dev": true, - "dependencies": { - "json-schema-to-ts": "^3.1.1" - }, - "bin": { - "anthropic-ai-sdk": "bin/cli" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } - } - }, - "node_modules/@aws-sdk/client-bedrock-runtime": { - "version": "3.1127.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1127.0.tgz", - "integrity": "sha512-IDl/lrPb90aH+pZFHGNDmgH9nAUQj5PlZH1sJ3w7RikctyjHSnY3oNjZhrLoaBoQn/rNK0zsP6OHEqEhj2tdLA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/credential-provider-node": "^3.972.82", - "@aws-sdk/eventstream-handler-node": "^3.972.34", - "@aws-sdk/middleware-eventstream": "^3.972.29", - "@aws-sdk/middleware-websocket": "^3.972.52", - "@aws-sdk/token-providers": "3.1127.0", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/node-http-handler": "^4.11.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.977.9", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.977.9.tgz", - "integrity": "sha512-reqPFEQrZxDZpeGj4PFMepBeR5LGYHRqq/L0motTzgFkCRBA4rFdaVXDSLYyGHhxVz7sT2PDnPN9CluGSfgyJA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@aws-sdk/xml-builder": "^3.972.40", - "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.33.3", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.17.2", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.70", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.70.tgz", - "integrity": "sha512-H404B7dJl2mCrBqahDEYsanB0xhdDp6tXnXcTUnXmmpy2Q3J0Ho0bUajZ2jr/RdwzCyS59Gi8xXIFwPLGBl6Uw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.72", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.72.tgz", - "integrity": "sha512-X98zYOrVOeuosCX+6ktf29FC2N2GHPLia7qv6mzPzTc+RPAuHWCDS++Z6JK7eGYqb/v6uaW7bAXaOvDBfol+0w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/node-http-handler": "^4.11.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.15", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.15.tgz", - "integrity": "sha512-Rykg6s5ceBuynMOGWgoowO4N+27JfnqXAnVaSunZl0hOO1XodSrxGNz6sCEbnmS0lAfQZDKyb3fbr46gSuv6Sg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/credential-provider-env": "^3.972.70", - "@aws-sdk/credential-provider-http": "^3.972.72", - "@aws-sdk/credential-provider-login": "^3.972.77", - "@aws-sdk/credential-provider-process": "^3.972.70", - "@aws-sdk/credential-provider-sso": "^3.973.14", - "@aws-sdk/credential-provider-web-identity": "^3.972.76", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.77", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.77.tgz", - "integrity": "sha512-Jb59xfEISoN5mmbnA+HYqdtrSX3CgCtJoof+V5D8/TgUI56W63GEEd5Y58WijU3Ou6+WEgaLD1feVzaRXV5IDQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.82", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.82.tgz", - "integrity": "sha512-znDkEOGXB8W3kG1LJUKP3foBZY/9qLM0eil/DxWXSp37XsdsRLQHE/d/OaCGGVgKpA6znR38h/+INk8do1FjiA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.70", - "@aws-sdk/credential-provider-http": "^3.972.72", - "@aws-sdk/credential-provider-ini": "^3.973.15", - "@aws-sdk/credential-provider-process": "^3.972.70", - "@aws-sdk/credential-provider-sso": "^3.973.14", - "@aws-sdk/credential-provider-web-identity": "^3.972.76", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.70", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.70.tgz", - "integrity": "sha512-2ry03fGRJr4sV3jI+ocjj5JqALnFD6ymM5KiNCDZMvq8bX2GSbE0vji4aM43TVCl2nXqqLRZaUxdq/KeWRAY4Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.14", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.14.tgz", - "integrity": "sha512-jkhg/8ocAAoc0RFyLMhCw+/zZh7gystQgd4F4hznNa8P4Cc501PQmxd+jGLiMHodPJ+7Zv/3znM62gZojyasmA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/token-providers": "3.1116.0", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.1116.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1116.0.tgz", - "integrity": "sha512-ygIivKqh8aHzNkucOCXHyIBgBpLPfrSI0mCqXF+vLBsPTUKqj0VSqAY0GFPe7lQl4HntjOcQ+KSyS7oUV2C54Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.76", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.76.tgz", - "integrity": "sha512-d3AGyVu759PGr35mEB2s22xxlNEA5rpdxtSPJthfPFJvoQ8dt357iVPECqWfUxXp1toJAvKmbtcIYVGigaGsCA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/eventstream-handler-node": { - "version": "3.972.34", - "resolved": "https://registry.npmjs.org/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.34.tgz", - "integrity": "sha512-cTeVzpu1xEAkryTZBYhGwnQ6gOGyp8ZYZvmn0Sg/nI/ABmy/CRHHxPDJDUi9PxwxUtGGaatvfRUB3FCgT/rSWw==", + "node_modules/@anthropic-ai/claude-agent-sdk": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.239.tgz", + "integrity": "sha512-cIuZhK4u76S5Otq78U890GSA6BFT4SLqOuMqzU/bP/tWRWKhHhNp/3/pvgLwoVGlkdhD7luXWduqXKyLC+VNBQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-eventstream": { - "version": "3.972.29", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.29.tgz", - "integrity": "sha512-dlRzHCgyB8W6hLuDC5pcT5q+ziPt00n4QGgGBE17ucLVU4zMa6lsbuUdQ2Pm75Z5VA8GF+R/+SgrRcaTdIzSIQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-websocket": { - "version": "3.972.52", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.52.tgz", - "integrity": "sha512-vsPPM+nMbKJlUCFU+eoGZbdxdxDIAX9LbpjSXaR5Ufpmqgp8TdYQnoExhLu4T3umW/JIIPny1ydbhWidZZYokQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.44", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.44.tgz", - "integrity": "sha512-NhEgryjlBF9w38ZXqGymQV28IhkYa1mKhlbYnqIis57AYwWGVYfUPgg/qC2rLRqOUfblxx++irvju10kVTa8Vw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/signature-v4-multi-region": "^3.996.46", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/fetch-http-handler": "^5.7.2", - "@smithy/node-http-handler": "^4.11.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.46", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.46.tgz", - "integrity": "sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.5", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.1127.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1127.0.tgz", - "integrity": "sha512-Dv2TMWBshJ+tF6ahs2Sy5bh4Iabsd4GAQqVvE9XZmYmnoaVbpS2QKIKE/HRacc7bTtbjEEvP+laGzHvHlf1CiQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.9", - "@aws-sdk/nested-clients": "^3.997.44", - "@aws-sdk/types": "^3.974.5", - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.974.5", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.5.tgz", - "integrity": "sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.40", - "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.40.tgz", - "integrity": "sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", - "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", - "dev": true, - "license": "Apache-2.0", + "license": "SEE LICENSE IN README.md", "engines": { "node": ">=18.0.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", - "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.29.8" - }, - "bin": { - "parser": "bin/babel-parser.js" }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", - "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@borewit/text-codec": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@borewit/text-codec/-/text-codec-0.2.2.tgz", - "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/@clack/core": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.3.0.tgz", - "integrity": "sha512-xJPHpAmEQUBrXSLx0gF+q5K/IyihXpsHZcha+jB+tyahsKRK3Dxo4D0coZDewHo12NhiuzC3dTtMPbm53GEAAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-wrap-ansi": "^0.2.0", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 20.12.0" - } - }, - "node_modules/@clack/prompts": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.3.0.tgz", - "integrity": "sha512-GgcWwRCs/xPtaqlMy8qRhPnZf9vlWcWZNHAitnVQ3yk7JmSralSiq5q07yaffYE8SogtDm7zFeKccx1QNVARpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@clack/core": "1.3.0", - "fast-string-width": "^3.0.2", - "fast-wrap-ansi": "^0.2.0", - "sisteransi": "^1.0.5" + "optionalDependencies": { + "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.239", + "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.239", + "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.239", + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.239", + "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.239", + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.239", + "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.239", + "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.239" }, - "engines": { - "node": ">= 20.12.0" + "peerDependencies": { + "@anthropic-ai/sdk": ">=0.93.0", + "@modelcontextprotocol/sdk": "^1.29.0", + "zod": "^4.0.0" } }, - "node_modules/@earendil-works/pi-agent-core": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.74.0.tgz", - "integrity": "sha512-6GMR7/wwjEJ1EsXLWEz03QOWin4AMrJ/AZoMpgm5DJ6GHsF6q6GOhQbj5Zip4dow3vo/TmBAVqM+vmGfrjGAFQ==", + "node_modules/@anthropic-ai/claude-agent-sdk-darwin-arm64": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.239.tgz", + "integrity": "sha512-GGVGuCwFEUm6cMlnBX0LTC9JX5NdGzxddbuqWtRxEgo9EetS70SO3FW+reitALlotHghPTfnICQILbBDIRyX+Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@earendil-works/pi-ai": "^0.74.0", - "typebox": "^1.1.24" - }, - "engines": { - "node": ">=20.0.0" - } + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@earendil-works/pi-ai": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.74.0.tgz", - "integrity": "sha512-7M7qcrZY/KEkH4wFkX3eqzvmKru4O88wezNKoN0KD2m4aAOmp9tdW2xCmUgSTSWlKB7b2Xw9QtAgrzHtg6t6iw==", + "node_modules/@anthropic-ai/claude-agent-sdk-darwin-x64": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.239.tgz", + "integrity": "sha512-QNbBXz3Pb3pQ7a+Kcbets6t9IrQhStKsfl5D518nYiGFoRMioO7efkZ6zHUcrGDqDC0LIzrs7tY2KNzH4RfwZA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@anthropic-ai/sdk": "^0.91.1", - "@aws-sdk/client-bedrock-runtime": "^3.1030.0", - "@google/genai": "^1.40.0", - "@mistralai/mistralai": "^2.2.0", - "chalk": "^5.6.2", - "openai": "6.26.0", - "partial-json": "^0.1.7", - "proxy-agent": "^6.5.0", - "typebox": "^1.1.24", - "undici": "^7.19.1", - "zod-to-json-schema": "^3.24.6" - }, - "bin": { - "pi-ai": "dist/cli.js" - }, - "engines": { - "node": ">=20.0.0" - } + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@earendil-works/pi-ai/node_modules/@google/genai": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.52.0.tgz", - "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", + "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.239.tgz", + "integrity": "sha512-RE6tDtzU0xj58tsuxnlXMJO8ckJ4tx/1nUgR+D/fPEQVt84oOyXeVspKt1ffvycogh3Sr3MkCGwZrPmxu/V1nA==", + "cpu": [ + "arm64" + ], "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "google-auth-library": "^10.3.0", - "p-retry": "^4.6.2", - "protobufjs": "^7.5.4", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@modelcontextprotocol/sdk": "^1.25.2" - }, - "peerDependenciesMeta": { - "@modelcontextprotocol/sdk": { - "optional": true - } - } + "libc": [ + "glibc" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@earendil-works/pi-ai/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64-musl": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.239.tgz", + "integrity": "sha512-Ajc3cuszVdOwfMZVsGdxrCTmgWOeJpQWAIqu8jNEvERIeNnBxvWfGrjmLPxYT3/LJ9Uj/tFTpp52J4IcmrJE5w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } + "libc": [ + "musl" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@earendil-works/pi-ai/node_modules/data-uri-to-buffer": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", - "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.239.tgz", + "integrity": "sha512-q4YaDoPgqh0XM23RM1/Zje7OSKccuCTQE89KoppDFOsyGdRsUj5xr01LTtr5hnYQuZD7dfwAbz9zl1g0MF/7TA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } + "libc": [ + "glibc" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@earendil-works/pi-ai/node_modules/degenerator": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", - "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.239.tgz", + "integrity": "sha512-zIUHiG4Romm/t6m/S9n8x4BKluyRCPk0147hPVo4xxkHkp4Di/7TnDMRKO3Wau4x361wRqlE2i5EpYT+CyJjHg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 14" - } + "libc": [ + "musl" + ], + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@earendil-works/pi-ai/node_modules/get-uri": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz", - "integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==", + "node_modules/@anthropic-ai/claude-agent-sdk-win32-arm64": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.239.tgz", + "integrity": "sha512-RxA29NdX9g3ZbpcXvSeWxpbg/Eoo3wXfO2eA1Vc7qa5JyAYjrl9xu6dIGAWMiyk/gnFxNh1WoFER77J9P6LTiQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "basic-ftp": "^5.0.2", - "data-uri-to-buffer": "^6.0.2", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@earendil-works/pi-ai/node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "node_modules/@anthropic-ai/claude-agent-sdk-win32-x64": { + "version": "0.3.239", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.239.tgz", + "integrity": "sha512-ylKIX0DfaK1EgWYbVEvBMYATVFdKjFcWvvypTIv2sJhM3KxJT/0lTzvqsai8jYeZN1FBHWlRNEUQJvJMjO/diA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } + "license": "SEE LICENSE IN LICENSE.md", + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@earendil-works/pi-ai/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "node_modules/@anthropic-ai/sdk": { + "version": "0.120.0", + "resolved": "https://mirrors.tencent.com/npm/@anthropic-ai/sdk/-/sdk-0.120.0.tgz", + "integrity": "sha512-ZlvmNFT/iIF6JD13rxbbMWD8nvGR0RaUp6yMQnoc+4Af0YjVVe/bIdW1XSQQsoxXAtg1NaT6Vak0LKFlJ4d37Q==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" + "json-schema-to-ts": "^3.1.1", + "standardwebhooks": "^1.0.0" }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/@earendil-works/pi-ai/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/@earendil-works/pi-ai/node_modules/openai": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.26.0.tgz", - "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", - "dev": true, - "license": "Apache-2.0", "bin": { - "openai": "bin/cli" + "anthropic-ai-sdk": "bin/cli" }, "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.25 || ^4.0" + "zod": "^3.25.0 || ^4.0.0" }, "peerDependenciesMeta": { - "ws": { - "optional": true - }, "zod": { "optional": true } } }, - "node_modules/@earendil-works/pi-ai/node_modules/pac-proxy-agent": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", - "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", - "dependencies": { - "@tootallnate/quickjs-emscripten": "^0.23.0", - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "get-uri": "^6.0.1", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.6", - "pac-resolver": "^7.0.1", - "socks-proxy-agent": "^8.0.5" - }, "engines": { - "node": ">= 14" + "node": ">=6.9.0" } }, - "node_modules/@earendil-works/pi-ai/node_modules/pac-resolver": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", - "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", - "dependencies": { - "degenerator": "^5.0.0", - "netmask": "^2.0.2" - }, "engines": { - "node": ">= 14" + "node": ">=6.9.0" } }, - "node_modules/@earendil-works/pi-ai/node_modules/proxy-agent": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", - "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "dev": true, - "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "http-proxy-agent": "^7.0.1", - "https-proxy-agent": "^7.0.6", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "^7.1.0", - "proxy-from-env": "^1.1.0", - "socks-proxy-agent": "^8.0.5" + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" }, "engines": { - "node": ">= 14" + "node": ">=6.0.0" } }, - "node_modules/@earendil-works/pi-ai/node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://mirrors.tencent.com/npm/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "dev": true, - "license": "MIT" + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@earendil-works/pi-ai/node_modules/socks-proxy-agent": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", - "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "dev": true, + "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { - "node": ">= 14" + "node": ">=6.9.0" } }, - "node_modules/@earendil-works/pi-ai/node_modules/undici": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", - "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=20.18.1" + "node": ">=18" } }, - "node_modules/@earendil-works/pi-coding-agent": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.74.0.tgz", - "integrity": "sha512-Q5GikbB5vRBrsrrf/uvet53rPSQ1sn5I5mO+l7sIobdXYpS04/X2oOc2UHFm90fNdkl3yU+ANTZL0zOtHbnqRw==", + "node_modules/@borewit/text-codec": { + "version": "0.2.2", + "resolved": "https://mirrors.tencent.com/npm/@borewit/text-codec/-/text-codec-0.2.2.tgz", + "integrity": "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==", "dev": true, "license": "MIT", - "dependencies": { - "@earendil-works/pi-agent-core": "^0.74.0", - "@earendil-works/pi-ai": "^0.74.0", - "@earendil-works/pi-tui": "^0.74.0", - "@silvia-odwyer/photon-node": "^0.3.4", - "chalk": "^5.5.0", - "cli-highlight": "^2.1.11", - "diff": "^8.0.2", - "extract-zip": "^2.0.1", - "file-type": "^21.1.1", - "glob": "^13.0.1", - "hosted-git-info": "^9.0.2", - "ignore": "^7.0.5", - "jiti": "^2.7.0", - "marked": "^15.0.12", - "minimatch": "^10.2.3", - "proper-lockfile": "^4.1.2", - "strip-ansi": "^7.1.0", - "typebox": "^1.1.24", - "undici": "^7.19.1", - "uuid": "^14.0.0", - "yaml": "^2.8.2" - }, - "bin": { - "pi": "dist/cli.js" - }, - "engines": { - "node": ">=20.6.0" - }, - "optionalDependencies": { - "@mariozechner/clipboard": "^0.3.5" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/@earendil-works/pi-coding-agent/node_modules/file-type": { - "version": "21.3.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz", - "integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==", + "node_modules/@clack/core": { + "version": "1.4.3", + "resolved": "https://mirrors.tencent.com/npm/@clack/core/-/core-1.4.3.tgz", + "integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==", "dev": true, "license": "MIT", "dependencies": { - "@tokenizer/inflate": "^0.4.1", - "strtok3": "^10.3.4", - "token-types": "^6.1.1", - "uint8array-extras": "^1.4.0" + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" }, "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" + "node": ">= 20.12.0" } }, - "node_modules/@earendil-works/pi-coding-agent/node_modules/undici": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", - "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", + "node_modules/@clack/prompts": { + "version": "1.7.0", + "resolved": "https://mirrors.tencent.com/npm/@clack/prompts/-/prompts-1.7.0.tgz", + "integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==", "dev": true, + "license": "MIT", + "dependencies": { + "@clack/core": "1.4.3", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, "engines": { - "node": ">=20.18.1" + "node": ">= 20.12.0" } }, "node_modules/@earendil-works/pi-tui": { - "version": "0.74.0", - "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.74.0.tgz", - "integrity": "sha512-1aIfXZp7D/z+1VlZX8BZcs6pgO8rjmil7kwyhctNDsWvce3Yfl8GVgu4eq+I0Mjhr8Cj+ipBiv9CLIzdoyCOIQ==", + "version": "0.84.2", + "resolved": "https://mirrors.tencent.com/npm/@earendil-works/pi-tui/-/pi-tui-0.84.2.tgz", + "integrity": "sha512-ds2TLihOnM5sLJB3VpXV6y0uR5efVuHf4MN7yDpsty6hA2DUO/EDVzjp/0od0G2JslzVLMjT8T8zavtxVb+qbg==", "dev": true, "license": "MIT", "dependencies": { - "@types/mime-types": "^2.1.4", - "chalk": "^5.5.0", - "get-east-asian-width": "^1.3.0", - "marked": "^15.0.12", - "mime-types": "^3.0.1" + "get-east-asian-width": "1.6.0", + "marked": "18.0.5" }, "engines": { - "node": ">=20.0.0" - }, - "optionalDependencies": { - "koffi": "^2.9.0" + "node": ">=22.19.0" } }, "node_modules/@esbuild/aix-ppc64": { @@ -1332,9 +789,9 @@ } }, "node_modules/@google/genai": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@google/genai/-/genai-2.0.1.tgz", - "integrity": "sha512-trxxbVePM9J8Cuni5x7+xvApoqb2y6Zk27/wugjT2cuwHOT78nFGdf/Ni29MkDxzWwrj90OQpno1Ana6dm3D2A==", + "version": "2.18.0", + "resolved": "https://mirrors.tencent.com/npm/@google/genai/-/genai-2.18.0.tgz", + "integrity": "sha512-uy9gWVTAZXuA/2tld0QJl/QNiGEn4QOmfX4PiRgZQmeFQRQhojpD/Gf41SPnBJmjEnT83a+h4AdU1HHYaYvVDw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -1389,16 +846,16 @@ } }, "node_modules/@grammyjs/types": { - "version": "3.26.0", - "resolved": "https://registry.npmjs.org/@grammyjs/types/-/types-3.26.0.tgz", - "integrity": "sha512-jlnyfxfev/2o68HlvAGRocAXgdPPX5QabG7jZlbqC2r9DZyWBfzTlg+nu3O3Fy4EhgLWu28hZ/8wr7DsNamP9A==", + "version": "4.0.0", + "resolved": "https://mirrors.tencent.com/npm/@grammyjs/types/-/types-4.0.0.tgz", + "integrity": "sha512-Z8lDLTvOlo12e5Vnly/vQh3JC9ppaitS1dGZ3w068gNitOd/y8tTSiib+Xm38aBGbtYGmUZwOc6afYrLs2CSTg==", "dev": true, "license": "MIT" }, "node_modules/@homebridge/ciao": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@homebridge/ciao/-/ciao-1.3.8.tgz", - "integrity": "sha512-lNhpCsZVbdbjz2trFjQdzQ3cUIMZQMIMksi7wd3ntTIYgdaGLqT1Ms97DfVIJYHzRuduf56ISvgU8RRLTpK/ng==", + "version": "1.3.12", + "resolved": "https://mirrors.tencent.com/npm/@homebridge/ciao/-/ciao-1.3.12.tgz", + "integrity": "sha512-84/0u0kqKy4qcKupIDaTtbkmk+3qFDuMzxTC0NPfVlHcUT+jHGdP+QCqwEw94/GJxRezDeBLwxaclkBZgCdeUg==", "dev": true, "license": "MIT", "dependencies": { @@ -1412,13 +869,13 @@ } }, "node_modules/@hono/node-server": { - "version": "1.19.17", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.17.tgz", - "integrity": "sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ==", + "version": "2.1.1", + "resolved": "https://mirrors.tencent.com/npm/@hono/node-server/-/node-server-2.1.1.tgz", + "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", "dev": true, "license": "MIT", "engines": { - "node": ">=18.14.1" + "node": ">=20" }, "peerDependencies": { "hono": "^4" @@ -1498,7 +955,7 @@ }, "node_modules/@isaacs/fs-minipass": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "dev": true, "license": "ISC", @@ -1556,39 +1013,78 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@lydell/node-pty": { - "version": "1.2.0-beta.12", - "resolved": "https://registry.npmjs.org/@lydell/node-pty/-/node-pty-1.2.0-beta.12.tgz", - "integrity": "sha512-qIK890UwPupoj07osVvgOIa++1mxeHbcGry4PKRHhNVNs81V2SCG34eJr46GybiOmBtc8Sj5PB1/GGM5PL549g==", + "node_modules/@koromix/koffi-darwin-arm64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-darwin-arm64/-/koffi-darwin-arm64-3.1.6.tgz", + "integrity": "sha512-8FHyXGCZN7/iQf4f7W5BRysmtdlAFvSx6FpmX4u6wmkZiX/2e9hIRdGLiZYlHGudlcA18UmXB/cMiyhJ7fJkzA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "optionalDependencies": { - "@lydell/node-pty-darwin-arm64": "1.2.0-beta.12", - "@lydell/node-pty-darwin-x64": "1.2.0-beta.12", - "@lydell/node-pty-linux-arm64": "1.2.0-beta.12", - "@lydell/node-pty-linux-x64": "1.2.0-beta.12", - "@lydell/node-pty-win32-arm64": "1.2.0-beta.12", - "@lydell/node-pty-win32-x64": "1.2.0-beta.12" + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" } }, - "node_modules/@lydell/node-pty-darwin-arm64": { - "version": "1.2.0-beta.12", - "resolved": "https://registry.npmjs.org/@lydell/node-pty-darwin-arm64/-/node-pty-darwin-arm64-1.2.0-beta.12.tgz", - "integrity": "sha512-tqaifcY9Cr41SblO1+FLzh8oxxtkNhuW9Dhl22lKme9BreYvKvxEZcdPIXTuqkJc5tagOEC4QHShKmJjLyLXLQ==", + "node_modules/@koromix/koffi-darwin-x64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-darwin-x64/-/koffi-darwin-x64-3.1.6.tgz", + "integrity": "sha512-uzx/jqFQuSHqgg1zaRidTBTCfj8Y9M0SDTO8HeoI9s9fJhiJ1mbB9TTwJO5c2hiMnuWg2m1byczC8BaIH6cG/w==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" - ] + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } }, - "node_modules/@lydell/node-pty-darwin-x64": { - "version": "1.2.0-beta.12", - "resolved": "https://registry.npmjs.org/@lydell/node-pty-darwin-x64/-/node-pty-darwin-x64-1.2.0-beta.12.tgz", - "integrity": "sha512-4LrS5pCJwqHKDVf1zS2gyNV0m4hKAXch+XZNhbZ6LY8uwVL8BhchzQBO40Os5anuRxRCWzHpw4Sp64Ie8q7E4Q==", + "node_modules/@koromix/koffi-freebsd-arm64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-freebsd-arm64/-/koffi-freebsd-arm64-3.1.6.tgz", + "integrity": "sha512-PjpTVrsCK5YTtixOw7VsseYXJOyoY6k0qBt+bf0T9h3wyV06y73rALsorFDDEoYpLUBZO7R6EIMs6CpUrEkNTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-ia32": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-freebsd-ia32/-/koffi-freebsd-ia32-3.1.6.tgz", + "integrity": "sha512-ETYwL820HtFwYoOVzgyvmFmzTHRo9DJtGYTxa5Nb7ajaa5ldCum0jbmUJ3PMECxFTLxD5Q6PYZ8Xbp101bGeSg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-x64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-freebsd-x64/-/koffi-freebsd-x64-3.1.6.tgz", + "integrity": "sha512-BkqxkNXhAAT9toU2stvLwx1iKHPDx7h08NCICyBbjYEXkCAEr84igTkpE5V3XJ9xZZ2gKll7VvdhxorHtHUqZw==", "cpu": [ "x64" ], @@ -1596,13 +1092,16 @@ "license": "MIT", "optional": true, "os": [ - "darwin" - ] + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } }, - "node_modules/@lydell/node-pty-linux-arm64": { - "version": "1.2.0-beta.12", - "resolved": "https://registry.npmjs.org/@lydell/node-pty-linux-arm64/-/node-pty-linux-arm64-1.2.0-beta.12.tgz", - "integrity": "sha512-Sx+A71x5BDGHt9ansfrtGxwq2VFVDWvJUAdlUL0Hv0qeiJUfts+hgopx+CgT4PSwahKjdEgtu0+FAfY9rICKRw==", + "node_modules/@koromix/koffi-linux-arm64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-linux-arm64/-/koffi-linux-arm64-3.1.6.tgz", + "integrity": "sha512-cM4XPm9ljbCrcPgXjzFYjDNxDUvvuR7TCYaEoo1AKjwZT/vmWhu2xN3pomfbsHh6aVn80SFA3enufQnaETW1rQ==", "cpu": [ "arm64" ], @@ -1611,40 +1110,66 @@ "optional": true, "os": [ "linux" - ] + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } }, - "node_modules/@lydell/node-pty-linux-x64": { - "version": "1.2.0-beta.12", - "resolved": "https://registry.npmjs.org/@lydell/node-pty-linux-x64/-/node-pty-linux-x64-1.2.0-beta.12.tgz", - "integrity": "sha512-bJzs94njofYhGg/UDqW1nj0dtvvu+2OvxMY+RlLS1T17VgcktKoIR6PuenTwE5HJ/D6StCPADmXcT0nNsCKmIQ==", + "node_modules/@koromix/koffi-linux-ia32": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-linux-ia32/-/koffi-linux-ia32-3.1.6.tgz", + "integrity": "sha512-l1SVTpO10iaQt8slbowJpzK4fbwQZ7ufj9tmCyAcIwWUpyAbPS83mJMctU72If6N9/gCS2wuRqwnYB2uPLLhLg==", "cpu": [ - "x64" + "ia32" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ] + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } }, - "node_modules/@lydell/node-pty-win32-arm64": { - "version": "1.2.0-beta.12", - "resolved": "https://registry.npmjs.org/@lydell/node-pty-win32-arm64/-/node-pty-win32-arm64-1.2.0-beta.12.tgz", - "integrity": "sha512-p7POgjVEiFaBC3/y+AKuV1FzePCsJ6HmZDv2XK+jBZSfwP8+uBAw181ZiKYN1YuRa/XpmBGaWezcI8hZkbW++g==", + "node_modules/@koromix/koffi-linux-loong64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-linux-loong64/-/koffi-linux-loong64-3.1.6.tgz", + "integrity": "sha512-KpTJpMSbIdCVFU26ynt0xy4x15h+y6AwPJxj2+iVxJhCzJf4oisCPc0YH2VnutuLV2nVzSrFm7sL/WSOqPgkXw==", "cpu": [ - "arm64" + "loong64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" - ] + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } }, - "node_modules/@lydell/node-pty-win32-x64": { - "version": "1.2.0-beta.12", - "resolved": "https://registry.npmjs.org/@lydell/node-pty-win32-x64/-/node-pty-win32-x64-1.2.0-beta.12.tgz", - "integrity": "sha512-IDFa00g7qUDGUYgByrUBJtC+mOjYVt/8KYyWivCg5JjGOHbBUACUQZLl0jTWmnr+tld/UyTpX90a2PY6oTVtRw==", + "node_modules/@koromix/koffi-linux-riscv64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-linux-riscv64/-/koffi-linux-riscv64-3.1.6.tgz", + "integrity": "sha512-YdFNpsywnXiYOYQlDAatf7TJLnspbGXdmfwIZhf82kbKSflYUsq4tI6NmoUOzM89oIWDGpYqd4Hz3xL7tsyXsw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-x64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-linux-x64/-/koffi-linux-x64-3.1.6.tgz", + "integrity": "sha512-Xx5mpr9VcaMCXfvbqIiLIWIL9Iuu6F4r3iMXg7+zZCqYUFZPFwJgiDQBLxctHv2OYgIfAoaaHMW0GC1cJkHfbA==", "cpu": [ "x64" ], @@ -1652,101 +1177,116 @@ "license": "MIT", "optional": true, "os": [ - "win32" - ] + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } }, - "node_modules/@mariozechner/clipboard": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard/-/clipboard-0.3.9.tgz", - "integrity": "sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA==", + "node_modules/@koromix/koffi-openbsd-ia32": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-openbsd-ia32/-/koffi-openbsd-ia32-3.1.6.tgz", + "integrity": "sha512-39Np4QTxhTlTT6RRveIeP+TnbzrwuDJ0UMyHxEZ+oGtzmb9GqWhl9T1oyehG6v/O+c4BffafG2NwLkCZ7tDKWw==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", "optional": true, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@mariozechner/clipboard-darwin-arm64": "0.3.9", - "@mariozechner/clipboard-darwin-universal": "0.3.9", - "@mariozechner/clipboard-darwin-x64": "0.3.9", - "@mariozechner/clipboard-linux-arm64-gnu": "0.3.9", - "@mariozechner/clipboard-linux-arm64-musl": "0.3.9", - "@mariozechner/clipboard-linux-riscv64-gnu": "0.3.9", - "@mariozechner/clipboard-linux-x64-gnu": "0.3.9", - "@mariozechner/clipboard-linux-x64-musl": "0.3.9", - "@mariozechner/clipboard-win32-arm64-msvc": "0.3.9", - "@mariozechner/clipboard-win32-x64-msvc": "0.3.9" - } - }, - "node_modules/@mariozechner/clipboard-darwin-arm64": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-arm64/-/clipboard-darwin-arm64-0.3.9.tgz", - "integrity": "sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ==", + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-x64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-openbsd-x64/-/koffi-openbsd-x64-3.1.6.tgz", + "integrity": "sha512-3EynGn3ycQRqaMWGmUJ0tdtuQdStByqSy/tJ0ZGKWizbMGdFAE73YpgLsyd8BDvwnKWytVG/OLNb5nDHpfd9Dg==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "openbsd" ], - "engines": { - "node": ">= 10" + "funding": { + "url": "https://liberapay.com/Koromix" } }, - "node_modules/@mariozechner/clipboard-darwin-universal": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-universal/-/clipboard-darwin-universal-0.3.9.tgz", - "integrity": "sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ==", + "node_modules/@koromix/koffi-win32-arm64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-win32-arm64/-/koffi-win32-arm64-3.1.6.tgz", + "integrity": "sha512-27FdPPRtT4xbO9bsd2OZa95M5YQ7bcJ8QjCRO57UUMI21REfkDegjqKwqo/CFlugxXlJf5IYtG2rq4BEYIrvxg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "win32" ], - "engines": { - "node": ">= 10" + "funding": { + "url": "https://liberapay.com/Koromix" } }, - "node_modules/@mariozechner/clipboard-darwin-x64": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-darwin-x64/-/clipboard-darwin-x64-0.3.9.tgz", - "integrity": "sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg==", + "node_modules/@koromix/koffi-win32-ia32": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-win32-ia32/-/koffi-win32-ia32-3.1.6.tgz", + "integrity": "sha512-5mVelLKVDup4eoxZOpCzCyMPxoctsg+Qe4J9O5BP4KbBEdqoOEqaNEBBRgNzXcdr2g+GGfmIUo+oVR1NvIdiJw==", "cpu": [ - "x64" + "ia32" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "win32" ], - "engines": { - "node": ">= 10" + "funding": { + "url": "https://liberapay.com/Koromix" } }, - "node_modules/@mariozechner/clipboard-linux-arm64-gnu": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-gnu/-/clipboard-linux-arm64-gnu-0.3.9.tgz", - "integrity": "sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw==", + "node_modules/@koromix/koffi-win32-x64": { + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/@koromix/koffi-win32-x64/-/koffi-win32-x64-3.1.6.tgz", + "integrity": "sha512-lPKjAaHz0aoiZXT/wDVqH+joR5y3lCZj1s9Bk5qx/DGRq+0MK8Ib8VoqiBOrJ69NG5AsJSvn0tQDcSqfRgLmBQ==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], - "engines": { - "node": ">= 10" + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@lydell/node-pty": { + "version": "1.2.0-beta.15", + "resolved": "https://mirrors.tencent.com/npm/@lydell/node-pty/-/node-pty-1.2.0-beta.15.tgz", + "integrity": "sha512-Br8wBxzbxFwdWgk9uQ+rdzE0xfoxOK4QuGH54swhRwc5IxP6H9Y1/bcyazRGvNUs6XkB5qNVkezuKSRxUwZe7A==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@lydell/node-pty-darwin-arm64": "1.2.0-beta.15", + "@lydell/node-pty-darwin-x64": "1.2.0-beta.15", + "@lydell/node-pty-linux-arm64": "1.2.0-beta.15", + "@lydell/node-pty-linux-x64": "1.2.0-beta.15", + "@lydell/node-pty-win32-arm64": "1.2.0-beta.15", + "@lydell/node-pty-win32-x64": "1.2.0-beta.15" } }, - "node_modules/@mariozechner/clipboard-linux-arm64-musl": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-arm64-musl/-/clipboard-linux-arm64-musl-0.3.9.tgz", - "integrity": "sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ==", + "node_modules/@lydell/node-pty-darwin-arm64": { + "version": "1.2.0-beta.15", + "resolved": "https://mirrors.tencent.com/npm/@lydell/node-pty-darwin-arm64/-/node-pty-darwin-arm64-1.2.0-beta.15.tgz", + "integrity": "sha512-6TSBbzdcLiNTHl1mTuzflqXrkmcC36USVGvERoDgvHk2ItEDaMaFZuAJ1CqPmwYj0DyhCS16TVS8OGK9xZnjyQ==", "cpu": [ "arm64" ], @@ -1754,50 +1294,41 @@ "license": "MIT", "optional": true, "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } + "darwin" + ] }, - "node_modules/@mariozechner/clipboard-linux-riscv64-gnu": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-riscv64-gnu/-/clipboard-linux-riscv64-gnu-0.3.9.tgz", - "integrity": "sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw==", + "node_modules/@lydell/node-pty-darwin-x64": { + "version": "1.2.0-beta.15", + "resolved": "https://mirrors.tencent.com/npm/@lydell/node-pty-darwin-x64/-/node-pty-darwin-x64-1.2.0-beta.15.tgz", + "integrity": "sha512-yDT2oqPqYMBScyuk1U9Rg5VKcrbMOD9o9jWYYamDADA3NSbUISroPChrqYRQ74Y7BQtNH4gqYAiWOZRi5uQZ0Q==", "cpu": [ - "riscv64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } + "darwin" + ] }, - "node_modules/@mariozechner/clipboard-linux-x64-gnu": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-gnu/-/clipboard-linux-x64-gnu-0.3.9.tgz", - "integrity": "sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw==", + "node_modules/@lydell/node-pty-linux-arm64": { + "version": "1.2.0-beta.15", + "resolved": "https://mirrors.tencent.com/npm/@lydell/node-pty-linux-arm64/-/node-pty-linux-arm64-1.2.0-beta.15.tgz", + "integrity": "sha512-wkbNF7dYAmtJv+o2+iztVlNwnUB4B0uX0wh/UD+mwMcmE2gNMnW9GChXO7fEE5XJokD0vB5idiHpGegaN+G/sg==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10" - } + ] }, - "node_modules/@mariozechner/clipboard-linux-x64-musl": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-linux-x64-musl/-/clipboard-linux-x64-musl-0.3.9.tgz", - "integrity": "sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ==", + "node_modules/@lydell/node-pty-linux-x64": { + "version": "1.2.0-beta.15", + "resolved": "https://mirrors.tencent.com/npm/@lydell/node-pty-linux-x64/-/node-pty-linux-x64-1.2.0-beta.15.tgz", + "integrity": "sha512-+U/5AVvHT6W+8OCYcnJgN0Qgc0ycO3TfD6aaFJHK+WHij797f8gsi5dV1HEO9l6YQmWCD+VL5gaLDhx3mxHwCA==", "cpu": [ "x64" ], @@ -1806,15 +1337,12 @@ "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10" - } + ] }, - "node_modules/@mariozechner/clipboard-win32-arm64-msvc": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-arm64-msvc/-/clipboard-win32-arm64-msvc-0.3.9.tgz", - "integrity": "sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ==", + "node_modules/@lydell/node-pty-win32-arm64": { + "version": "1.2.0-beta.15", + "resolved": "https://mirrors.tencent.com/npm/@lydell/node-pty-win32-arm64/-/node-pty-win32-arm64-1.2.0-beta.15.tgz", + "integrity": "sha512-pyAk91w7wnnKrD4mrHXtIXRfmzSWV5bEzvRhurXcMCtCc2TJ424ciUskIgWMhAPP6y3KyUnqElj+U6kY3iOt0A==", "cpu": [ "arm64" ], @@ -1823,15 +1351,12 @@ "optional": true, "os": [ "win32" - ], - "engines": { - "node": ">= 10" - } + ] }, - "node_modules/@mariozechner/clipboard-win32-x64-msvc": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@mariozechner/clipboard-win32-x64-msvc/-/clipboard-win32-x64-msvc-0.3.9.tgz", - "integrity": "sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA==", + "node_modules/@lydell/node-pty-win32-x64": { + "version": "1.2.0-beta.15", + "resolved": "https://mirrors.tencent.com/npm/@lydell/node-pty-win32-x64/-/node-pty-win32-x64-1.2.0-beta.15.tgz", + "integrity": "sha512-2f8twEmDVxZ7drchAXjtevpmSPhFok0avAnzXro4t5gmz0xsPNKkoZvymwtuIS3xo7PzQqZOPQ/YzwEMb7oIzQ==", "cpu": [ "x64" ], @@ -1840,17 +1365,13 @@ "optional": true, "os": [ "win32" - ], - "engines": { - "node": ">= 10" - } + ] }, "node_modules/@mistralai/mistralai": { "version": "2.6.4", - "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-2.6.4.tgz", + "resolved": "https://mirrors.tencent.com/npm/@mistralai/mistralai/-/mistralai-2.6.4.tgz", "integrity": "sha512-PPt4GyJqs2hEsWrYCJZK5f0ORmT+L2MSm75LVGD7kBLf6ZKsoDpld/FRBQXr8xG6iFCBOFJFYzvGYhUb+UCkbw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@opentelemetry/semantic-conventions": "^1.40.0", "ws": "^8.18.0", @@ -1879,14 +1400,13 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", - "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", + "version": "1.30.0", + "resolved": "https://mirrors.tencent.com/npm/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", + "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@hono/node-server": "^1.19.9", + "@hono/node-server": "^1.19.9 || ^2.0.5", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", @@ -1930,209 +1450,10 @@ "node": ">=14.0.0" } }, - "node_modules/@napi-rs/canvas": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.100.tgz", - "integrity": "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==", - "dev": true, - "license": "MIT", - "optional": true, - "workspaces": [ - "e2e/*" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@napi-rs/canvas-android-arm64": "0.1.100", - "@napi-rs/canvas-darwin-arm64": "0.1.100", - "@napi-rs/canvas-darwin-x64": "0.1.100", - "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", - "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", - "@napi-rs/canvas-linux-arm64-musl": "0.1.100", - "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", - "@napi-rs/canvas-linux-x64-gnu": "0.1.100", - "@napi-rs/canvas-linux-x64-musl": "0.1.100", - "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", - "@napi-rs/canvas-win32-x64-msvc": "0.1.100" - } - }, - "node_modules/@napi-rs/canvas-android-arm64": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz", - "integrity": "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-darwin-arm64": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz", - "integrity": "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-darwin-x64": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz", - "integrity": "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz", - "integrity": "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-arm64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz", - "integrity": "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-arm64-musl": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz", - "integrity": "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz", - "integrity": "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-x64-gnu": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz", - "integrity": "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-linux-x64-musl": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz", - "integrity": "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==", + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", "cpu": [ "x64" ], @@ -2143,110 +1464,58 @@ "linux" ], "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/canvas-win32-arm64-msvc": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz", - "integrity": "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" + "node": "^22.20 || ^24.12 || >=25" } }, - "node_modules/@napi-rs/canvas-win32-x64-msvc": { - "version": "0.1.100", - "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz", - "integrity": "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==", - "cpu": [ - "x64" - ], + "node_modules/@openclaw/ai": { + "version": "2026.8.1", + "resolved": "https://mirrors.tencent.com/npm/@openclaw/ai/-/ai-2026.8.1.tgz", + "integrity": "sha512-gUhfqsEZMRkgNZFegBMhKV5fw5OTziw+Pk2w0hOwOpNkT2W20VL2uS5Yz3ZbiC4snd5BQDBmmO33cVUgwr2aUg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@anthropic-ai/sdk": "0.120.0", + "@google/genai": "2.18.0", + "@mistralai/mistralai": "2.6.4", + "openai": "7.5.0", + "partial-json": "0.1.7", + "typebox": "1.3.16" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@napi-rs/lzma-linux-x64-gnu": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", - "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": "^22.20 || ^24.12 || >=25" + "node": ">=22.19.0" } }, "node_modules/@openclaw/fs-safe": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@openclaw/fs-safe/-/fs-safe-0.2.4.tgz", - "integrity": "sha512-Fo3WTQhxu0asD/rZqIKBqhX6fuZfjyHxSW5yTKfcRx+D9BRAcz0AGoVh+3ur/4XRvZkvsh3Ud8XTw006yRYLgg==", + "version": "0.5.6", + "resolved": "https://mirrors.tencent.com/npm/@openclaw/fs-safe/-/fs-safe-0.5.6.tgz", + "integrity": "sha512-0M1vz1PEFAgCwTxhB1lt/B7z+TRTTWmlYJ3dSbdhjZp2AcfM7rXPGjQVJqHXpzpsb9SRxvKGrAM454Uul/Xy5g==", "dev": true, - "license": "MIT", "engines": { - "node": ">=20.11" + "node": ">=22" }, "optionalDependencies": { "jszip": "^3.10.1", - "tar": "7.5.13" + "tar": "7.5.22" } }, - "node_modules/@openclaw/fs-safe/node_modules/tar": { - "version": "7.5.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", - "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", + "node_modules/@openclaw/proxyline": { + "version": "0.3.7", + "resolved": "https://mirrors.tencent.com/npm/@openclaw/proxyline/-/proxyline-0.3.7.tgz", + "integrity": "sha512-RWkt4mPcBOj7E8euyeqynkIFXvEIxVStYH0YHDC08feq5qFyBXGmfdWC+MTMVJXfHN2ituoxLlrIyjpyJpW7ew==", "dev": true, - "license": "BlueOak-1.0.0", - "optional": true, - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=22.19.0" + }, + "peerDependencies": { + "undici": ">=8.5.0 <9" } }, "node_modules/@opentelemetry/semantic-conventions": { "version": "1.43.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=14" } @@ -2910,34 +2179,33 @@ }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/@protobufjs/base64": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/base64/-/base64-1.1.2.tgz", "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/@protobufjs/codegen": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/codegen/-/codegen-2.0.5.tgz", "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/fetch/-/fetch-1.1.1.tgz", "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", "dev": true, "dependencies": { @@ -2946,29 +2214,31 @@ }, "node_modules/@protobufjs/float": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/float/-/float-1.0.2.tgz", "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/path/-/path-1.1.2.tgz", "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/pool/-/pool-1.1.0.tgz", "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/@protobufjs/utf8/-/utf8-1.1.2.tgz", "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.63.1", @@ -3317,103 +2587,43 @@ "win32" ] }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://mirrors.tencent.com/npm/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, "node_modules/@silvia-odwyer/photon-node": { "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@silvia-odwyer/photon-node/-/photon-node-0.3.4.tgz", + "resolved": "https://mirrors.tencent.com/npm/@silvia-odwyer/photon-node/-/photon-node-0.3.4.tgz", "integrity": "sha512-bnly4BKB3KDTFxrUIcgCLbaeVVS8lrAkri1pEzskpmxu9MdfGQTy8b8EgcD83ywD3RPMsIulY8xJH5Awa+t9fA==", "dev": true, "license": "Apache-2.0" }, - "node_modules/@smithy/core": { - "version": "3.33.3", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.33.3.tgz", - "integrity": "sha512-CsOeKq/9kA3y6VJHt+/+VTCtBaxJ4OTFpgrjIUhPpDIKxBci1k2bJaQASF2h/ELWrulGp+t97DZ0mevfAD8idg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", - "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.8.0.tgz", - "integrity": "sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.18.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.1.tgz", - "integrity": "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==", + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://mirrors.tencent.com/npm/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.18.0", - "tslib": "^2.6.2" - }, + "license": "MIT", "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.3.tgz", - "integrity": "sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.3", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" + "node": ">=18" }, - "engines": { - "node": ">=18.0.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@smithy/types": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.18.0.tgz", - "integrity": "sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A==", + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://mirrors.tencent.com/npm/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } + "license": "MIT" }, "node_modules/@tokenizer/inflate": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@tokenizer/inflate/-/inflate-0.4.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/@tokenizer/inflate/-/inflate-0.4.1.tgz", "integrity": "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==", "dev": true, "license": "MIT", @@ -3431,17 +2641,119 @@ }, "node_modules/@tokenizer/token": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/@tokenizer/token/-/token-0.3.0.tgz", "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", "dev": true, "license": "MIT" }, - "node_modules/@tootallnate/quickjs-emscripten": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "node_modules/@trycua/cua-driver": { + "version": "0.21.0", + "resolved": "https://mirrors.tencent.com/npm/@trycua/cua-driver/-/cua-driver-0.21.0.tgz", + "integrity": "sha512-5oe8+1mm40pvMYSuXvPf5RTMPITgeGAUJhwQkkrL8nX57Goe2n5zs48q5e5kpT+jaGwGuxX4PotOn5UuNVSymA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@ubjs/core": "0.31.0-3", + "@ubjs/node": "0.31.0-3" + }, + "optionalDependencies": { + "@trycua/cua-driver-darwin-arm64": "0.21.0", + "@trycua/cua-driver-darwin-x64": "0.21.0", + "@trycua/cua-driver-linux-arm64-gnu": "0.21.0", + "@trycua/cua-driver-linux-x64-gnu": "0.21.0", + "@trycua/cua-driver-win32-arm64-msvc": "0.21.0", + "@trycua/cua-driver-win32-x64-msvc": "0.21.0" + } + }, + "node_modules/@trycua/cua-driver-darwin-arm64": { + "version": "0.21.0", + "resolved": "https://mirrors.tencent.com/npm/@trycua/cua-driver-darwin-arm64/-/cua-driver-darwin-arm64-0.21.0.tgz", + "integrity": "sha512-wiQRixfS+zkakpcBI1zAfPQrE3slN1mozvkcFYgp0HufuzDuO/aShX+qLrTyw1a0MiKa7JjjyNdPXpJBE1wUiA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT AND MPL-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@trycua/cua-driver-darwin-x64": { + "version": "0.21.0", + "resolved": "https://mirrors.tencent.com/npm/@trycua/cua-driver-darwin-x64/-/cua-driver-darwin-x64-0.21.0.tgz", + "integrity": "sha512-MFWkXLESSmr1LxE8FGwNWWUcZgZM+4kIFSPCV6uwy5W2ctSn5O/G4DrjjCAiuONRZzMpU0jlovcfQEB55Eje4g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT AND MPL-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@trycua/cua-driver-linux-arm64-gnu": { + "version": "0.21.0", + "resolved": "https://mirrors.tencent.com/npm/@trycua/cua-driver-linux-arm64-gnu/-/cua-driver-linux-arm64-gnu-0.21.0.tgz", + "integrity": "sha512-Udb+CeHmogSndIR8yChucYPg70zFqAC595ykeXOWUOs+oGE2QN1a92uJRZSqCYtx1hi2MkLamW/tQksigJTFrw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT AND MPL-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@trycua/cua-driver-linux-x64-gnu": { + "version": "0.21.0", + "resolved": "https://mirrors.tencent.com/npm/@trycua/cua-driver-linux-x64-gnu/-/cua-driver-linux-x64-gnu-0.21.0.tgz", + "integrity": "sha512-CuT/FNR2/zShtIK6cSbIZVCUc6khlH88SgQi8w1mYjDx7xEDyuLxuoBhu9JRpMKDvj2EOf4bqlSUOBa4zJSSyA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT AND MPL-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@trycua/cua-driver-win32-arm64-msvc": { + "version": "0.21.0", + "resolved": "https://mirrors.tencent.com/npm/@trycua/cua-driver-win32-arm64-msvc/-/cua-driver-win32-arm64-msvc-0.21.0.tgz", + "integrity": "sha512-qVwBJgsYHyhP/LZih0km+TJrVcV4vFB8h1URtcYgHgiZ+XdT/WwXzTAuB/34+gb2acyI2oddQPw/JQE3klM5Lw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT AND MPL-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@trycua/cua-driver-win32-x64-msvc": { + "version": "0.21.0", + "resolved": "https://mirrors.tencent.com/npm/@trycua/cua-driver-win32-x64-msvc/-/cua-driver-win32-x64-msvc-0.21.0.tgz", + "integrity": "sha512-BTHCfX2t6ht6TsJxIBjBxF3FfkMVsuOuakOqCBRhE8eYbfhouqKHHF8dwwCtOKk6g1KJSOkYC83+Qkq2yuoVdQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT AND MPL-2.0", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@types/chai": { "version": "5.2.3", @@ -3468,13 +2780,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/mime-types": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz", - "integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/node": { "version": "26.4.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-26.4.1.tgz", @@ -3487,21 +2792,158 @@ }, "node_modules/@types/retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true, "license": "MIT" }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "node_modules/@ubjs/core": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/core/-/core-0.31.0-3.tgz", + "integrity": "sha512-39XrJgUZ2VVb561sSnkXPhczNoeBsNiSRArecsV0JE7CJq69ajFkcn9/tBAUS2NpgHkLIDU+z6Ks2+1wXnboxg==", "dev": true, - "license": "MIT", + "license": "MPL-2.0" + }, + "node_modules/@ubjs/node": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node/-/node-0.31.0-3.tgz", + "integrity": "sha512-qNMpi2LICNwxGXZyRF8fSDBSpbezyZbEsydrbiMPJOmtOWr4tmZIEl7jkWGHVGShoBvHfFo4eHp5B4UVP928Cg==", + "dev": true, + "license": "MPL-2.0", + "optionalDependencies": { + "@ubjs/node-darwin-arm64": "0.31.0-3", + "@ubjs/node-darwin-x64": "0.31.0-3", + "@ubjs/node-linux-arm64-gnu": "0.31.0-3", + "@ubjs/node-linux-arm64-musl": "0.31.0-3", + "@ubjs/node-linux-x64-gnu": "0.31.0-3", + "@ubjs/node-linux-x64-musl": "0.31.0-3", + "@ubjs/node-win32-arm64-msvc": "0.31.0-3", + "@ubjs/node-win32-x64-msvc": "0.31.0-3" + } + }, + "node_modules/@ubjs/node-darwin-arm64": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node-darwin-arm64/-/node-darwin-arm64-0.31.0-3.tgz", + "integrity": "sha512-GGQVPLkVo4Gc8qVLW4IGvS8bjl8eHXyeP4a97ntGmsAdXwE5gsS29o8xUEFROjhwHKD+9sgVeblCSWVG3CpHsw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", "optional": true, - "dependencies": { - "@types/node": "*" - } + "os": [ + "darwin" + ] + }, + "node_modules/@ubjs/node-darwin-x64": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node-darwin-x64/-/node-darwin-x64-0.31.0-3.tgz", + "integrity": "sha512-2sc47u4XFYOsbmP5EW+Gx8m/yGrYnfFDFQm6+kz7goSWTNg84eEiz3COs9HKJDVuNJ5Khv5XipTO8CFadMLXCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@ubjs/node-linux-arm64-gnu": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node-linux-arm64-gnu/-/node-linux-arm64-gnu-0.31.0-3.tgz", + "integrity": "sha512-YStVXhYz/5jvlWf/p4fhiVT72unYAbGugifFC9QmO/+hnroQDAQ5t8SARbsc15G4olMcamdIB+GETiUB7gmaYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ubjs/node-linux-arm64-musl": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node-linux-arm64-musl/-/node-linux-arm64-musl-0.31.0-3.tgz", + "integrity": "sha512-Izp4nvfy/LmibzFowAztkoDOksCR2fb2zl6fh1ojR1HEsg0rAGruxtI8d3fn8DI0lBXwqmn6SF///oD4mFNJPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ubjs/node-linux-x64-gnu": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node-linux-x64-gnu/-/node-linux-x64-gnu-0.31.0-3.tgz", + "integrity": "sha512-Xdm21blyg5U/kW6s7OMvgrr8coGTkUlt26DVR9x8gKISif+E3YwdEskbFScWqystAiJnfjw7xHEc8UMu0Qlz7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ubjs/node-linux-x64-musl": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node-linux-x64-musl/-/node-linux-x64-musl-0.31.0-3.tgz", + "integrity": "sha512-fFQ9BWS6i2LUH9SJgD9oEiKXXo/say59vHy7usFe1t7C2xvwvP34f5SuxXmWP9R8fHyA0aC4kIZ+TTwyHSv1Kw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@ubjs/node-win32-arm64-msvc": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node-win32-arm64-msvc/-/node-win32-arm64-msvc-0.31.0-3.tgz", + "integrity": "sha512-ID6rSz1NmPsWTNBBNAw4OnJ5Dj8pcbtNJtdPB3OxcGigLBd/e0x7buhSI7os6Mo5iYtEdCynBRQHFJwub5XSPg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@ubjs/node-win32-x64-msvc": { + "version": "0.31.0-3", + "resolved": "https://mirrors.tencent.com/npm/@ubjs/node-win32-x64-msvc/-/node-win32-x64-msvc-0.31.0-3.tgz", + "integrity": "sha512-wevs+Y+szwcCUT8IJFbB4/1nfxyRv/51l8oG7FGUPWD1xLPyuHfJBG27C+PDeC7KRzes/2n6aLo4DGZbr/LYTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@vitest/coverage-v8": { "version": "3.2.7", @@ -3666,30 +3108,42 @@ }, "node_modules/accepts": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/accepts/-/accepts-2.0.0.tgz", "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://mirrors.tencent.com/npm/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "bin": { + "acorn": "bin/acorn" }, "engines": { - "node": ">= 0.6" + "node": ">=0.4.0" } }, "node_modules/agent-base": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", - "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", + "version": "7.1.4", + "resolved": "https://mirrors.tencent.com/npm/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 20" + "node": ">= 14" } }, "node_modules/ajv": { "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/ajv/-/ajv-8.20.0.tgz", "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "dependencies": { @@ -3705,7 +3159,7 @@ }, "node_modules/ajv-formats": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/ajv-formats/-/ajv-formats-3.0.1.tgz", "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", "dev": true, "dependencies": { @@ -3748,19 +3202,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/asn1.js": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", @@ -3783,18 +3224,6 @@ "node": ">=12" } }, - "node_modules/ast-types": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", - "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "dev": true, - "dependencies": { - "tslib": "^2.0.1" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/ast-v8-to-istanbul": { "version": "0.3.12", "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.12.tgz", @@ -3819,7 +3248,7 @@ }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, "funding": [ @@ -3835,25 +3264,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" - }, - "node_modules/basic-ftp": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz", - "integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - } + ] }, "node_modules/bignumber.js": { "version": "9.3.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/bignumber.js/-/bignumber.js-9.3.1.tgz", "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", "dev": true, - "license": "MIT", "engines": { "node": "*" } @@ -3867,9 +3284,10 @@ }, "node_modules/body-parser": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/body-parser/-/body-parser-2.3.0.tgz", "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "dev": true, + "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^2.0.0", @@ -3891,9 +3309,10 @@ }, "node_modules/body-parser/node_modules/content-type": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/content-type/-/content-type-2.1.0.tgz", "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -3903,11 +3322,18 @@ } }, "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "version": "2.0.0", + "resolved": "https://mirrors.tencent.com/npm/boolbase/-/boolbase-2.0.0.tgz", + "integrity": "sha512-DkVaaQHymRhpYEYo9x1oo7Q7B0Y6KJUsjm3c9eTyFDby4MHLBTwZ6ZDWBel5zrYxj1WsZgC5oLpiz+93MluXeA==", "dev": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } }, "node_modules/bottleneck": { "version": "2.19.5", @@ -3916,13 +3342,6 @@ "dev": true, "license": "MIT" }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "dev": true, - "license": "MIT" - }, "node_modules/brace-expansion": { "version": "5.0.9", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", @@ -3936,16 +3355,6 @@ "node": "20 || >=22" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -3955,16 +3364,17 @@ }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true, "license": "MIT" }, "node_modules/bytes": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3981,10 +3391,9 @@ }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" @@ -3995,7 +3404,7 @@ }, "node_modules/call-bound": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "resolved": "https://mirrors.tencent.com/npm/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", @@ -4037,12 +3446,13 @@ } }, "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "version": "6.0.0", + "resolved": "https://mirrors.tencent.com/npm/chalk/-/chalk-6.0.0.tgz", + "integrity": "sha512-2uNTXIuTTxk7ciZgAU1BQcgnchcG0xXnrs6jzkQfj9SsRa9M2s5zE8WT96hS6KmG4MzWHSrvH43DF1m4XRkrFg==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" + "node": ">=22" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" @@ -4075,81 +3485,25 @@ }, "node_modules/chownr": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/chownr/-/chownr-3.0.0.tgz", "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": ">=18" } }, - "node_modules/cli-highlight": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", - "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "node_modules/clawpdf": { + "version": "0.3.1", + "resolved": "https://mirrors.tencent.com/npm/clawpdf/-/clawpdf-0.3.1.tgz", + "integrity": "sha512-HZ8gz3cm8arzT/V2CnMZlHlRJbsrUYQ71u+A4nymeyvNnYzpZ8RQwkr2EIZiXCOzRkzFy8sOiHBXBuSUDDcXqQ==", "dev": true, - "license": "ISC", - "dependencies": { - "chalk": "^4.0.0", - "highlight.js": "^10.7.1", - "mz": "^2.4.0", - "parse5": "^5.1.1", - "parse5-htmlparser2-tree-adapter": "^6.0.0", - "yargs": "^16.0.0" - }, + "license": "MIT", "bin": { - "highlight": "bin/highlight" - }, - "engines": { - "node": ">=8.0.0", - "npm": ">=5.0.0" - } - }, - "node_modules/cli-highlight/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" + "clawpdf": "dist/cli.js" }, "engines": { - "node": ">=8" + "node": ">=22" } }, "node_modules/color-convert": { @@ -4172,18 +3526,18 @@ "dev": true }, "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "version": "15.0.0", + "resolved": "https://mirrors.tencent.com/npm/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", "dev": true, "license": "MIT", "engines": { - "node": ">=20" + "node": ">=22.12.0" } }, "node_modules/content-disposition": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/content-disposition/-/content-disposition-1.1.0.tgz", "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", "dev": true, "engines": { @@ -4196,25 +3550,27 @@ }, "node_modules/content-type": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "resolved": "https://mirrors.tencent.com/npm/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie": { "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/cookie/-/cookie-0.7.2.tgz", "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-signature": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/cookie-signature/-/cookie-signature-1.2.2.tgz", "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "dev": true, "license": "MIT", @@ -4224,17 +3580,15 @@ }, "node_modules/core-util-is": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cors": { "version": "2.8.6", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "resolved": "https://mirrors.tencent.com/npm/cors/-/cors-2.8.6.tgz", "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "dev": true, - "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -4283,45 +3637,50 @@ } }, "node_modules/css-select": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", - "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "version": "7.0.0", + "resolved": "https://mirrors.tencent.com/npm/css-select/-/css-select-7.0.0.tgz", + "integrity": "sha512-snmjEVXy+1LnwXdxhYvTMj1d9tOh4HxkA1YmoayVBeeyR2C14Pum7fcxJIm4SswYspVy866eYNwlH6xC3/VH5g==", "dev": true, "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" + "boolbase": "^2.0.0", + "css-what": "^8.0.0", + "domhandler": "^6.0.1", + "domutils": "^4.0.2", + "nth-check": "^3.0.1" + }, + "engines": { + "node": ">=20.19.0" }, "funding": { + "type": "github", "url": "https://github.com/sponsors/fb55" } }, "node_modules/css-what": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", - "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "version": "8.0.0", + "resolved": "https://mirrors.tencent.com/npm/css-what/-/css-what-8.0.0.tgz", + "integrity": "sha512-DH0Bqq3DNp5tdOReuNyAA+Ev4Y2GS5FMbZpeTLP6C4CDi0h5nL0BmUPChXw3o/qbHLDWHl49sbNqQVY7bMSDdw==", "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">= 6" + "node": ">=20.19.0" }, "funding": { + "type": "github", "url": "https://github.com/sponsors/fb55" } }, "node_modules/cssom": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/cssom/-/cssom-0.5.0.tgz", "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", "dev": true }, "node_modules/data-uri-to-buffer": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", "dev": true, - "license": "MIT", "engines": { "node": ">= 12" } @@ -4362,63 +3721,9 @@ "node": ">=6" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/degenerator": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-7.0.1.tgz", - "integrity": "sha512-ABErK0IefDSyHjlPH7WUEenIAX2rPPnrDcDM+TS3z3+zu9TfyKKi07BQM+8rmxpdE2y1v5fjjdoAS/x4D2U60w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ast-types": "^0.13.4", - "escodegen": "^2.1.0", - "esprima": "^4.0.1" - }, - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "quickjs-wasi": "^2.2.0" - } - }, "node_modules/depd": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "engines": { @@ -4426,9 +3731,9 @@ } }, "node_modules/diff": { - "version": "8.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", - "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "version": "9.0.0", + "resolved": "https://mirrors.tencent.com/npm/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", "dev": true, "engines": { "node": ">=0.3.1" @@ -4442,58 +3747,73 @@ "license": "MIT" }, "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "version": "3.1.1", + "resolved": "https://mirrors.tencent.com/npm/dom-serializer/-/dom-serializer-3.1.1.tgz", + "integrity": "sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==", "dev": true, + "license": "MIT", "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" + "domelementtype": "^3.0.0", + "domhandler": "^6.0.0", + "entities": "^8.0.0" + }, + "engines": { + "node": ">=20.19.0" }, "funding": { + "type": "github", "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "version": "3.0.0", + "resolved": "https://mirrors.tencent.com/npm/domelementtype/-/domelementtype-3.0.0.tgz", + "integrity": "sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + } }, "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "version": "6.0.1", + "resolved": "https://mirrors.tencent.com/npm/domhandler/-/domhandler-6.0.1.tgz", + "integrity": "sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "domelementtype": "^2.3.0" + "domelementtype": "^3.0.0" }, "engines": { - "node": ">= 4" + "node": ">=20.19.0" }, "funding": { + "type": "github", "url": "https://github.com/fb55/domhandler?sponsor=1" } }, "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "version": "4.0.2", + "resolved": "https://mirrors.tencent.com/npm/domutils/-/domutils-4.0.2.tgz", + "integrity": "sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" + "dom-serializer": "^3.0.0", + "domelementtype": "^3.0.0", + "domhandler": "^6.0.0" + }, + "engines": { + "node": ">=20.19.0" }, "funding": { + "type": "github", "url": "https://github.com/fb55/domutils?sponsor=1" } }, @@ -4512,9 +3832,10 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, + "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", @@ -4542,10 +3863,9 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -4556,30 +3876,22 @@ }, "node_modules/encodeurl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "version": "8.0.0", + "resolved": "https://mirrors.tencent.com/npm/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -4587,17 +3899,16 @@ }, "node_modules/es-define-property": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-errors": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "engines": { @@ -4613,7 +3924,7 @@ }, "node_modules/es-object-atoms": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/es-object-atoms/-/es-object-atoms-1.1.2.tgz", "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "dev": true, "license": "MIT", @@ -4678,66 +3989,10 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } + "license": "MIT" }, "node_modules/estree-walker": { "version": "3.0.3", @@ -4749,18 +4004,9 @@ "@types/estree": "^1.0.0" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/etag": { "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, "license": "MIT", @@ -4779,9 +4025,10 @@ }, "node_modules/eventsource": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "resolved": "https://mirrors.tencent.com/npm/eventsource/-/eventsource-3.0.7.tgz", "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", "dev": true, + "license": "MIT", "dependencies": { "eventsource-parser": "^3.0.1" }, @@ -4791,12 +4038,39 @@ }, "node_modules/eventsource-parser": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/eventsource-parser/-/eventsource-parser-3.1.1.tgz", "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=18.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/execa": { + "version": "10.0.1", + "resolved": "https://mirrors.tencent.com/npm/execa/-/execa-10.0.1.tgz", + "integrity": "sha512-ge98qjkRK4IB7tL7Ju/6qmm5LHoH1eEMt5FNZrz3f4UIYhF28lggX20z3FaX1sgc67msLEn0N0BscOs29iuwyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "figures": "^6.1.0", + "get-stream": "^9.0.1", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.3.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "which-command": "^0.1.0", + "yoctocolors": "^2.1.2" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, "node_modules/expect-type": { @@ -4811,11 +4085,10 @@ }, "node_modules/express": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/express/-/express-5.2.1.tgz", "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", @@ -4856,10 +4129,9 @@ }, "node_modules/express-rate-limit": { "version": "8.7.0", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.7.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/express-rate-limit/-/express-rate-limit-8.7.0.tgz", "integrity": "sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.4.3", "ip-address": "^10.2.0" @@ -4876,49 +4148,34 @@ }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true, "license": "MIT" }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://mirrors.tencent.com/npm/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "dev": true, + "license": "Unlicense" + }, "node_modules/fast-string-truncated-width": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-string-width": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/fast-string-width/-/fast-string-width-3.0.2.tgz", "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", "dev": true, "license": "MIT", @@ -4928,7 +4185,7 @@ }, "node_modules/fast-uri": { "version": "3.1.7", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz", + "resolved": "https://mirrors.tencent.com/npm/fast-uri/-/fast-uri-3.1.7.tgz", "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==", "dev": true, "funding": [ @@ -4940,12 +4197,11 @@ "type": "opencollective", "url": "https://opencollective.com/fastify" } - ], - "license": "BSD-3-Clause" + ] }, "node_modules/fast-wrap-ansi": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", "dev": true, "license": "MIT", @@ -4953,16 +4209,6 @@ "fast-string-width": "^3.0.2" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -4983,7 +4229,7 @@ }, "node_modules/fetch-blob": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/fetch-blob/-/fetch-blob-3.2.0.tgz", "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", "dev": true, "funding": [ @@ -5005,10 +4251,26 @@ "node": "^12.20 || >= 14.13" } }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://mirrors.tencent.com/npm/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/file-type": { - "version": "22.0.1", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-22.0.1.tgz", - "integrity": "sha512-ww5Mhre0EE+jmBvOXTmXAbEMuZE7uX4a3+oRCQFNj8w++g3ev913N6tXQz0XTXbueQ5TWQfm6BdaViEHHn8bhA==", + "version": "22.0.2", + "resolved": "https://mirrors.tencent.com/npm/file-type/-/file-type-22.0.2.tgz", + "integrity": "sha512-0H8TsCUGBLx+V5adH3EY52hTAcyLKbV1D4gq5cIOJ6DnQAHeV9Z2Hhuc5CoBX4YmvB2oL+JIC84z0qO7JsCoNw==", "dev": true, "license": "MIT", "dependencies": { @@ -5026,9 +4288,10 @@ }, "node_modules/finalhandler": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/finalhandler/-/finalhandler-2.1.1.tgz", "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", @@ -5074,21 +4337,9 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/formdata-polyfill": { "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "resolved": "https://mirrors.tencent.com/npm/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", "dev": true, "license": "MIT", @@ -5101,7 +4352,7 @@ }, "node_modules/forwarded": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", "dev": true, "license": "MIT", @@ -5111,7 +4362,7 @@ }, "node_modules/fresh": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/fresh/-/fresh-2.0.0.tgz", "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "dev": true, "license": "MIT", @@ -5135,7 +4386,7 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "funding": { @@ -5144,7 +4395,7 @@ }, "node_modules/gaxios": { "version": "7.3.1", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.3.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/gaxios/-/gaxios-7.3.1.tgz", "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", "dev": true, "dependencies": { @@ -5156,33 +4407,9 @@ "node": ">=18" } }, - "node_modules/gaxios/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/gaxios/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/gcp-metadata": { "version": "8.1.2", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/gcp-metadata/-/gcp-metadata-8.1.2.tgz", "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", "dev": true, "license": "Apache-2.0", @@ -5207,9 +4434,10 @@ }, "node_modules/get-east-asian-width": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -5219,7 +4447,7 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", @@ -5244,10 +4472,9 @@ }, "node_modules/get-proto": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, - "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" @@ -5257,98 +4484,24 @@ } }, "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "version": "9.0.1", + "resolved": "https://mirrors.tencent.com/npm/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", "dev": true, - "license": "MIT", "dependencies": { - "pump": "^3.0.0" + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-uri": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-8.0.0.tgz", - "integrity": "sha512-CqtZlMKvfJeY0Zxv8wazDwXmSKmnMnsmNy8j8+wudi8EyG/pMUB1NqHc+Tv1QaNtpYsK9nOYjb7r7Ufu32RPSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "basic-ftp": "^5.2.0", - "data-uri-to-buffer": "8.0.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/get-uri/node_modules/data-uri-to-buffer": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-8.0.0.tgz", - "integrity": "sha512-6UHfyCux51b8PTGDgveqtz1tvphBku5DrMKKJbFAZAJOI2zsjDpDoYE1+QGj7FOMS4BdTFNJsJiR3zEB0xH0yQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20" - } - }, - "node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/global-agent": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-4.1.3.tgz", - "integrity": "sha512-KUJEViiuFT3I97t+GYMikLPJS2Lfo/S2F+DQuBWzuzaMPnvt5yyZePzArx36fBzpGTxZjIpDbXLeySLgh+k76g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "globalthis": "^1.0.2", - "matcher": "^4.0.0", - "semver": "^7.3.5", - "serialize-error": "^8.1.0" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/google-auth-library": { "version": "10.9.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.9.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/google-auth-library/-/google-auth-library-10.9.1.tgz", "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", "dev": true, "license": "Apache-2.0", @@ -5366,7 +4519,7 @@ }, "node_modules/google-logging-utils": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/google-logging-utils/-/google-logging-utils-1.1.3.tgz", "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", "dev": true, "license": "Apache-2.0", @@ -5376,7 +4529,7 @@ }, "node_modules/gopd": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", @@ -5387,21 +4540,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, "node_modules/grammy": { - "version": "1.42.0", - "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.42.0.tgz", - "integrity": "sha512-1AdCge+AkjSdp2FwfICSFnVbl8Mq3KVHJDy+DgTI9+D6keJ0zWALPRKas5jv/8psiCzL4N2cEOcGW7O45Kn39g==", + "version": "1.45.1", + "resolved": "https://mirrors.tencent.com/npm/grammy/-/grammy-1.45.1.tgz", + "integrity": "sha512-Y4VL/hqJMZZxwlUr5ZgM68CFu2iIeEkNLR1cY3+Ww68CIvWARDsoXFix7+31rmyC0+7L85ZI+Pq3E5JSG5+nLQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@grammyjs/types": "3.26.0", + "@grammyjs/types": "4.0.0", "abort-controller": "^3.0.0", "debug": "^4.4.3", "node-fetch": "^2.7.0" @@ -5439,22 +4585,9 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "engines": { @@ -5466,9 +4599,10 @@ }, "node_modules/hasown": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "resolved": "https://mirrors.tencent.com/npm/hasown/-/hasown-2.0.4.tgz", "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -5477,37 +4611,36 @@ } }, "node_modules/highlight.js": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", - "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "version": "11.12.0", + "resolved": "https://mirrors.tencent.com/npm/highlight.js/-/highlight.js-11.12.0.tgz", + "integrity": "sha512-nbfWpyRMcMrPMmDwJB+dhX/eiaPKtc2RB+0QZskqJ3WjRA/FDS0e9hZrx8EC/lbEv8gXy98FcDbNa/dspAaJMg==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": "*" + "node": ">=12.0.0" } }, "node_modules/hono": { "version": "4.13.7", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.7.tgz", + "resolved": "https://mirrors.tencent.com/npm/hono/-/hono-4.13.7.tgz", "integrity": "sha512-c8/gF9ac8Y78/agExVocyLevgR+JlpNB444Py0FSX8pJoPdYUfUzRcXtYEYGwt6l19qIlVZPN5Mfsw9jFShmQQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=16.9.0" } }, "node_modules/hosted-git-info": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz", - "integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==", + "version": "10.1.1", + "resolved": "https://mirrors.tencent.com/npm/hosted-git-info/-/hosted-git-info-10.1.1.tgz", + "integrity": "sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ==", "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^11.1.0" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" } }, "node_modules/html-escaper": { @@ -5518,7 +4651,7 @@ }, "node_modules/htmlparser2": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/htmlparser2/-/htmlparser2-10.1.0.tgz", "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", "dev": true, "funding": [ @@ -5528,7 +4661,6 @@ "url": "https://github.com/sponsors/fb55" } ], - "license": "MIT", "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.3", @@ -5536,11 +4668,83 @@ "entities": "^7.0.1" } }, + "node_modules/htmlparser2/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://mirrors.tencent.com/npm/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/htmlparser2/node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://mirrors.tencent.com/npm/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/htmlparser2/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://mirrors.tencent.com/npm/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/htmlparser2/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://mirrors.tencent.com/npm/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/htmlparser2/node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://mirrors.tencent.com/npm/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/htmlparser2/node_modules/entities": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/entities/-/entities-7.0.1.tgz", "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.12" }, @@ -5560,7 +4764,7 @@ }, "node_modules/http-errors": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/http-errors/-/http-errors-2.0.1.tgz", "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", @@ -5579,37 +4783,33 @@ "url": "https://opencollective.com/express" } }, - "node_modules/http-proxy-agent": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-9.0.0.tgz", - "integrity": "sha512-FcF8VhXYLQcxWCnt/cCpT2apKsRDUGeVEeMqGu4HSTu29U8Yw0TLOjdYIlDsYk3IkUh+taX4IDWpPcCqKDhCjA==", + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://mirrors.tencent.com/npm/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4" + "agent-base": "^7.1.2", + "debug": "4" }, "engines": { - "node": ">= 20" + "node": ">= 14" } }, - "node_modules/https-proxy-agent": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.0.0.tgz", - "integrity": "sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g==", + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://mirrors.tencent.com/npm/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 20" + "node": ">=18.18.0" } }, "node_modules/iconv-lite": { "version": "0.7.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/iconv-lite/-/iconv-lite-0.7.3.tgz", "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", "dev": true, "dependencies": { @@ -5625,7 +4825,7 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true, "funding": [ @@ -5645,9 +4845,9 @@ "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "7.0.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.8.tgz", - "integrity": "sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==", + "version": "7.0.6", + "resolved": "https://mirrors.tencent.com/npm/ignore/-/ignore-7.0.6.tgz", + "integrity": "sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw==", "dev": true, "engines": { "node": ">= 4" @@ -5655,7 +4855,7 @@ }, "node_modules/immediate": { "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "resolved": "https://mirrors.tencent.com/npm/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "dev": true, "license": "MIT" @@ -5669,7 +4869,7 @@ }, "node_modules/ip-address": { "version": "10.7.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/ip-address/-/ip-address-10.7.0.tgz", "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==", "dev": true, "license": "MIT", @@ -5678,36 +4878,76 @@ } }, "node_modules/ipaddr.js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.4.0.tgz", - "integrity": "sha512-9VGk3HGanVE6JoZXHiCpnGy5X0jYDnN4EA4lntFPj+1vIWlFhIylq2CrrCOJH9EAhc5CYhq18F2Av2tgoAPsYQ==", + "version": "1.9.1", + "resolved": "https://mirrors.tencent.com/npm/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://mirrors.tencent.com/npm/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://mirrors.tencent.com/npm/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://mirrors.tencent.com/npm/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://mirrors.tencent.com/npm/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true - }, "node_modules/isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", @@ -5796,11 +5036,10 @@ } }, "node_modules/jose": { - "version": "6.2.11", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.11.tgz", - "integrity": "sha512-A5NPn7g8EAzGU3IzRs+Yiq8K5n3ypYS75M5+KKiVHdUexfpWK1kP4ZMq7QnTGDoMj6TJ1dtcEJjW60yZDXS4hg==", + "version": "6.2.12", + "resolved": "https://mirrors.tencent.com/npm/jose/-/jose-6.2.12.tgz", + "integrity": "sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } @@ -5813,7 +5052,7 @@ }, "node_modules/json-bigint": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/json-bigint/-/json-bigint-1.0.0.tgz", "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", "dev": true, "license": "MIT", @@ -5823,7 +5062,7 @@ }, "node_modules/json-schema-to-ts": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", "dev": true, "license": "MIT", @@ -5837,16 +5076,17 @@ }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, "node_modules/json-schema-typed": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/json-schema-typed/-/json-schema-typed-8.0.2.tgz", "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/json5": { "version": "2.2.3", @@ -5863,10 +5103,9 @@ }, "node_modules/jszip": { "version": "3.10.1", - "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "dev": true, - "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -5898,21 +5137,37 @@ } }, "node_modules/koffi": { - "version": "2.16.3", - "resolved": "https://registry.npmjs.org/koffi/-/koffi-2.16.3.tgz", - "integrity": "sha512-E9y1AsgYGlaxMhcZzHr8y96QF2U5XzA12GGVAfbWqIubTwPNMXQarfBzePNXHe0xtIEtNd6ifAv3GAKYGUeBAQ==", + "version": "3.1.6", + "resolved": "https://mirrors.tencent.com/npm/koffi/-/koffi-3.1.6.tgz", + "integrity": "sha512-ln60chEb3o7Du1ayjwl6BFiNN1wZK+3cTM2wWGiHLEzCY/FdTIN1ER5VWDwHq7J/j4tSnnrHaH5ABS1EO6+6ag==", "dev": true, "hasInstallScript": true, "license": "MIT", - "optional": true, "funding": { "url": "https://liberapay.com/Koromix" + }, + "optionalDependencies": { + "@koromix/koffi-darwin-arm64": "3.1.6", + "@koromix/koffi-darwin-x64": "3.1.6", + "@koromix/koffi-freebsd-arm64": "3.1.6", + "@koromix/koffi-freebsd-ia32": "3.1.6", + "@koromix/koffi-freebsd-x64": "3.1.6", + "@koromix/koffi-linux-arm64": "3.1.6", + "@koromix/koffi-linux-ia32": "3.1.6", + "@koromix/koffi-linux-loong64": "3.1.6", + "@koromix/koffi-linux-riscv64": "3.1.6", + "@koromix/koffi-linux-x64": "3.1.6", + "@koromix/koffi-openbsd-ia32": "3.1.6", + "@koromix/koffi-openbsd-x64": "3.1.6", + "@koromix/koffi-win32-arm64": "3.1.6", + "@koromix/koffi-win32-ia32": "3.1.6", + "@koromix/koffi-win32-x64": "3.1.6" } }, "node_modules/kysely": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/kysely/-/kysely-0.29.0.tgz", - "integrity": "sha512-LrQfPUeTW7MXbMvT62moEMnpMTuj9TO3lqjCeLKjM975PJ4Alrl/43f2tlDX7xOsNptKgH4LSNGwIbXwEkLg4g==", + "version": "0.29.5", + "resolved": "https://mirrors.tencent.com/npm/kysely/-/kysely-0.29.5.tgz", + "integrity": "sha512-ooa+eSbBNPTo3MycPEuW5jdrxQdQwdtB3LC3h43FiXQbIry5tR0C5lDG7eealK0E4D7XjrnOP5DIUg/LyjRMYQ==", "dev": true, "license": "MIT", "engines": { @@ -5921,24 +5176,25 @@ }, "node_modules/lie": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, + "license": "MIT", "dependencies": { "immediate": "~3.0.5" } }, "node_modules/linkedom": { - "version": "0.18.12", - "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.18.12.tgz", - "integrity": "sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q==", + "version": "0.18.13", + "resolved": "https://mirrors.tencent.com/npm/linkedom/-/linkedom-0.18.13.tgz", + "integrity": "sha512-ES/o9qotMpzpN2MHs+Iq/JcVoOj8Fa5wiQYrTdFpvAnwXL0g66XHHUc9WUMk6nAlBtGsFQ24ne+SYnvnaQ2FSw==", "dev": true, "license": "ISC", "dependencies": { - "css-select": "^5.1.0", + "css-select": "^7.0.0", "cssom": "^0.5.0", "html-escaper": "^3.0.3", - "htmlparser2": "^10.0.0", + "htmlparser2": "^10.1.0", "uhyphen": "^0.2.0" }, "engines": { @@ -5955,28 +5211,10 @@ }, "node_modules/linkedom/node_modules/html-escaper": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/html-escaper/-/html-escaper-3.0.3.tgz", "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", - "dev": true - }, - "node_modules/linkify-it": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", - "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/markdown-it" - } - ], - "dependencies": { - "uc.micro": "^2.0.0" - } + "license": "MIT" }, "node_modules/locate-path": { "version": "5.0.0", @@ -5992,9 +5230,10 @@ }, "node_modules/long": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/long/-/long-5.3.2.tgz", "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/loupe": { "version": "3.2.1", @@ -6005,10 +5244,9 @@ }, "node_modules/lru-cache": { "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/lru-cache/-/lru-cache-11.5.2.tgz", "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, - "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } @@ -6049,56 +5287,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/markdown-it": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", - "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, "node_modules/marked": { - "version": "15.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", - "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", + "version": "18.0.5", + "resolved": "https://mirrors.tencent.com/npm/marked/-/marked-18.0.5.tgz", + "integrity": "sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==", "dev": true, "license": "MIT", "bin": { "marked": "bin/marked.js" }, "engines": { - "node": ">= 18" - } - }, - "node_modules/matcher": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/matcher/-/matcher-4.0.0.tgz", - "integrity": "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 20" } }, "node_modules/math-intrinsics": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", @@ -6106,18 +5310,11 @@ "node": ">= 0.4" } }, - "node_modules/mdurl": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz", - "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", - "dev": true - }, "node_modules/media-typer": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/media-typer/-/media-typer-1.1.1.tgz", "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" }, @@ -6128,10 +5325,9 @@ }, "node_modules/merge-descriptors": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -6141,17 +5337,16 @@ }, "node_modules/mime-db": { "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-3.0.2.tgz", "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", @@ -6174,13 +5369,12 @@ "license": "ISC" }, "node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "version": "10.2.6", + "resolved": "https://mirrors.tencent.com/npm/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.5" + "brace-expansion": "^5.0.8" }, "engines": { "node": "18 || 20 || >=22" @@ -6211,9 +5405,10 @@ }, "node_modules/minizlib": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/minizlib/-/minizlib-3.1.0.tgz", "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "dev": true, + "license": "MIT", "dependencies": { "minipass": "^7.1.2" }, @@ -6228,18 +5423,6 @@ "dev": true, "license": "MIT" }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "node_modules/nanoid": { "version": "3.3.18", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", @@ -6261,7 +5444,7 @@ }, "node_modules/negotiator": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/negotiator/-/negotiator-1.1.0.tgz", "integrity": "sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==", "dev": true, "license": "MIT", @@ -6278,9 +5461,10 @@ }, "node_modules/negotiator/node_modules/content-type": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/content-type/-/content-type-2.1.0.tgz", "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -6289,16 +5473,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/netmask": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz", - "integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/node-addon-api": { "version": "8.9.2", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.9.2.tgz", @@ -6311,7 +5485,7 @@ }, "node_modules/node-domexception": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/node-domexception/-/node-domexception-1.0.0.tgz", "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", "deprecated": "Use your platform's native DOMException instead", "dev": true, @@ -6345,16 +5519,6 @@ "node-edge-tts": "bin.js" } }, - "node_modules/node-edge-tts/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, "node_modules/node-edge-tts/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -6378,20 +5542,6 @@ "node": ">=12" } }, - "node_modules/node-edge-tts/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/node-edge-tts/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -6433,7 +5583,7 @@ }, "node_modules/node-fetch": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/node-fetch/-/node-fetch-3.3.2.tgz", "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", "dev": true, "dependencies": { @@ -6461,21 +5611,54 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://mirrors.tencent.com/npm/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://mirrors.tencent.com/npm/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "version": "3.0.1", + "resolved": "https://mirrors.tencent.com/npm/nth-check/-/nth-check-3.0.1.tgz", + "integrity": "sha512-GX0gsdbGVCgnRgbeGaubfjpBXyYRWOOCVeYh08bSQvDZqxz5ndXs1OTfAt/h36G1xvI94YIspsI0sVFqAV9+RQ==", "dev": true, "dependencies": { - "boolbase": "^1.0.0" + "boolbase": "^2.0.0" + }, + "engines": { + "node": ">=20.19.0" }, "funding": { + "type": "github", "url": "https://github.com/fb55/nth-check?sponsor=1" } }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, "engines": { @@ -6484,7 +5667,7 @@ }, "node_modules/object-inspect": { "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "resolved": "https://mirrors.tencent.com/npm/object-inspect/-/object-inspect-1.13.4.tgz", "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "engines": { @@ -6494,22 +5677,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/on-finished": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -6519,7 +5691,7 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { @@ -6527,19 +5699,31 @@ } }, "node_modules/openai": { - "version": "6.37.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-6.37.0.tgz", - "integrity": "sha512-0H5dEGFmmLv6KSd0W1w2nyL8WsLkX6yoLeQpU+dZAOuGcany5qkYQMmj35ZrKgb6yiyYqpUzFOpR8mZQkgqeEQ==", + "version": "7.5.0", + "resolved": "https://mirrors.tencent.com/npm/openai/-/openai-7.5.0.tgz", + "integrity": "sha512-ZbDBz8FSB8Mv8fFYIUvzTFMdV5vl93/octp1MdtK2lfYepSpfv/ewmeugpKz/cwGtFSx+YuUM4NwpZ2P55YiPA==", "dev": true, "license": "Apache-2.0", - "bin": { - "openai": "bin/cli" + "engines": { + "node": ">=22.0.0" }, "peerDependencies": { + "@aws-sdk/credential-provider-node": ">=3.972.0 <4", + "@smithy/hash-node": ">=4.3.0 <5", + "@smithy/signature-v4": ">=5.4.0 <6", "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "peerDependenciesMeta": { + "@aws-sdk/credential-provider-node": { + "optional": true + }, + "@smithy/hash-node": { + "optional": true + }, + "@smithy/signature-v4": { + "optional": true + }, "ws": { "optional": true }, @@ -6549,62 +5733,77 @@ } }, "node_modules/openclaw": { - "version": "2026.5.12", - "resolved": "https://registry.npmjs.org/openclaw/-/openclaw-2026.5.12.tgz", - "integrity": "sha512-hHg88OFSF0rhDNUbmjMEJO0UdnGn4mNq0F23Hk/NmTKY3OaPCUXiHutd8Ea6S5TGouponytMMWCYgPRrwsW2Xg==", + "version": "2026.8.1", + "resolved": "https://mirrors.tencent.com/npm/openclaw/-/openclaw-2026.8.1.tgz", + "integrity": "sha512-bSaFeaDFnQH/bU1vgKMac6eHkHHPHG0C/uwduXGI3eIS3lyiYSwmDU5ehhBUUhlPeV85tL5/KVwmoH48nX1tWw==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { - "@agentclientprotocol/sdk": "0.21.0", - "@clack/core": "1.3.0", - "@clack/prompts": "1.3.0", - "@earendil-works/pi-agent-core": "0.74.0", - "@earendil-works/pi-ai": "0.74.0", - "@earendil-works/pi-coding-agent": "0.74.0", - "@earendil-works/pi-tui": "0.74.0", - "@google/genai": "2.0.1", + "@agentclientprotocol/sdk": "1.4.0", + "@anthropic-ai/claude-agent-sdk": "0.3.239", + "@anthropic-ai/sdk": "0.120.0", + "@clack/core": "1.4.3", + "@clack/prompts": "1.7.0", + "@earendil-works/pi-tui": "0.84.2", + "@google/genai": "2.18.0", "@grammyjs/runner": "2.0.3", "@grammyjs/transformer-throttler": "1.2.1", - "@homebridge/ciao": "1.3.8", - "@lydell/node-pty": "1.2.0-beta.12", - "@modelcontextprotocol/sdk": "1.29.0", + "@homebridge/ciao": "1.3.12", + "@lydell/node-pty": "1.2.0-beta.15", + "@mistralai/mistralai": "2.6.4", + "@modelcontextprotocol/sdk": "1.30.0", "@mozilla/readability": "0.6.0", - "@openclaw/fs-safe": "0.2.4", - "ajv": "8.20.0", - "chalk": "5.6.2", + "@openclaw/ai": "2026.8.1", + "@openclaw/fs-safe": "0.5.6", + "@openclaw/proxyline": "0.3.7", + "@silvia-odwyer/photon-node": "0.3.4", + "@trycua/cua-driver": "0.21.0", + "acorn": "8.18.0", + "chalk": "6.0.0", "chokidar": "5.0.0", - "commander": "14.0.3", + "clawpdf": "0.3.1", + "commander": "15.0.0", "croner": "10.0.1", + "diff": "9.0.0", "dotenv": "17.4.2", + "entities": "8.0.0", + "execa": "10.0.1", "express": "5.2.1", - "file-type": "22.0.1", - "global-agent": "4.1.3", - "grammy": "1.42.0", - "https-proxy-agent": "9.0.0", - "ipaddr.js": "2.4.0", + "file-type": "22.0.2", + "grammy": "1.45.1", + "highlight.js": "11.12.0", + "hosted-git-info": "10.1.1", + "iconv-lite": "0.7.3", + "ignore": "7.0.6", "jiti": "2.7.0", "json5": "2.2.3", "jszip": "3.10.1", - "kysely": "0.29.0", - "linkedom": "0.18.12", - "markdown-it": "14.1.1", - "minimatch": "10.2.5", + "koffi": "3.1.6", + "kysely": "0.29.5", + "linkedom": "0.18.13", + "minimatch": "10.2.6", + "ms": "2.1.3", "node-edge-tts": "1.2.10", - "openai": "6.37.0", - "pdfjs-dist": "5.7.284", - "playwright-core": "1.60.0", - "proxy-agent": "8.0.1", + "openai": "7.5.0", + "p-limit": "7.3.1", + "p-map": "7.0.6", + "partial-json": "0.1.7", + "playwright-core": "1.62.1", + "pretty-ms": "9.3.0", "qrcode": "1.5.4", - "tar": "7.5.15", - "tokenjuice": "0.7.0", + "quickjs-wasi": "3.5.0", + "rastermill": "0.3.2", + "semver": "7.8.5", + "tar": "7.5.22", "tree-sitter-bash": "0.25.1", - "tslog": "4.10.2", - "typebox": "1.1.38", - "undici": "8.2.0", + "tslog": "4.11.0", + "typebox": "1.3.16", + "typescript": "6.0.3", + "undici": "8.10.0", "web-push": "3.6.7", - "web-tree-sitter": "0.26.8", - "ws": "8.20.0", + "web-tree-sitter": "0.26.12", + "ws": "8.21.3", "yaml": "2.9.0", "zod": "4.4.3" }, @@ -6612,12 +5811,42 @@ "openclaw": "openclaw.mjs" }, "engines": { - "node": ">=22.16.0" + "node": ">=22.22.3 <23 || >=24.15.0 <25 || >=25.9.0" }, "optionalDependencies": { "sqlite-vec": "0.1.9" } }, + "node_modules/openclaw/node_modules/p-limit": { + "version": "7.3.1", + "resolved": "https://mirrors.tencent.com/npm/p-limit/-/p-limit-7.3.1.tgz", + "integrity": "sha512-0trZaiG7Y7kN/Egy9a8j47t9osC0Tch4PaIWd9yGF6bvmlk7muExRvGNYb8sXBwEKMoNKsbNN9P8EefuQekE4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^1.2.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openclaw/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://mirrors.tencent.com/npm/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/oxfmt": { "version": "0.60.0", "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.60.0.tgz", @@ -6747,9 +5976,22 @@ "node": ">=8" } }, + "node_modules/p-map": { + "version": "7.0.6", + "resolved": "https://mirrors.tencent.com/npm/p-map/-/p-map-7.0.6.tgz", + "integrity": "sha512-I4Prw6ivkd6p8PiYR1tXASOAOBzIJwu0TB7fqaX0c/8c3QAehNYmX57EijyGGGBt3c/BIowGwV03RVBtXvHEVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-retry": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/p-retry/-/p-retry-4.6.2.tgz", "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, "license": "MIT", @@ -6771,43 +6013,6 @@ "node": ">=6" } }, - "node_modules/pac-proxy-agent": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-9.0.1.tgz", - "integrity": "sha512-3ZOSpLboOlpW4yp8Cuv21KlTULRqyJ5Uuad3wXpSKFrxdNgcHEyoa22GRaZ2UlgCVuR6z+5BiavtYVvbajL/Yw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4", - "get-uri": "8.0.0", - "http-proxy-agent": "9.0.0", - "https-proxy-agent": "9.0.0", - "pac-resolver": "9.0.1", - "quickjs-wasi": "^2.2.0", - "socks-proxy-agent": "10.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/pac-resolver": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-9.0.1.tgz", - "integrity": "sha512-lJbS008tmkj08VhoM8Hzuv/VE5tK9MS0OIQ/7+s0lIF+BYhiQWFYzkSpML7lXs9iBu2jfmzBTLzhe9n6BX+dYw==", - "dev": true, - "license": "MIT", - "dependencies": { - "degenerator": "7.0.1", - "netmask": "^2.0.2" - }, - "engines": { - "node": ">= 20" - }, - "peerDependencies": { - "quickjs-wasi": "^2.2.0" - } - }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -6816,48 +6021,35 @@ }, "node_modules/pako": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "resolved": "https://mirrors.tencent.com/npm/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true, - "license": "(MIT AND Zlib)" - }, - "node_modules/parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", - "dev": true, - "license": "MIT" + "dev": true }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://mirrors.tencent.com/npm/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", "dev": true, "license": "MIT", - "dependencies": { - "parse5": "^6.0.1" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true, - "license": "MIT" - }, "node_modules/parseurl": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/partial-json": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/partial-json/-/partial-json-0.1.7.tgz", + "resolved": "https://mirrors.tencent.com/npm/partial-json/-/partial-json-0.1.7.tgz", "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", "dev": true, "license": "MIT" @@ -6881,26 +6073,9 @@ "node": ">=8" } }, - "node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/path-to-regexp": { "version": "8.4.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/path-to-regexp/-/path-to-regexp-8.4.2.tgz", "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", "dev": true, "funding": { @@ -6925,25 +6100,6 @@ "node": ">= 14.16" } }, - "node_modules/pdfjs-dist": { - "version": "5.7.284", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.7.284.tgz", - "integrity": "sha512-h4EdYQczmGhbOlqc3PPZwxevn7ApdWPbovAuWXOB/DjIyigSnwfy2oze7c6mRcSr9XgLp3eN3EeL4DyySTPMFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=22.13.0 || >=24" - }, - "optionalDependencies": { - "@napi-rs/canvas": "^0.1.100" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -6955,7 +6111,6 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", "dev": true, - "peer": true, "engines": { "node": ">=12" }, @@ -6965,7 +6120,7 @@ }, "node_modules/pkce-challenge": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/pkce-challenge/-/pkce-challenge-5.0.1.tgz", "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", "dev": true, "license": "MIT", @@ -6974,16 +6129,16 @@ } }, "node_modules/playwright-core": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", - "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "version": "1.62.1", + "resolved": "https://mirrors.tencent.com/npm/playwright-core/-/playwright-core-1.62.1.tgz", + "integrity": "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==", "dev": true, "license": "Apache-2.0", "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=18" + "node": ">=20" } }, "node_modules/pngjs": { @@ -7025,36 +6180,31 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/proper-lockfile": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "node_modules/pretty-ms": { + "version": "9.3.0", + "resolved": "https://mirrors.tencent.com/npm/pretty-ms/-/pretty-ms-9.3.0.tgz", + "integrity": "sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==", "dev": true, "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" - } - }, - "node_modules/proper-lockfile/node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, + "parse-ms": "^4.0.0" + }, "engines": { - "node": ">= 4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://mirrors.tencent.com/npm/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, "node_modules/protobufjs": { "version": "7.6.6", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz", + "resolved": "https://mirrors.tencent.com/npm/protobufjs/-/protobufjs-7.6.6.tgz", "integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==", "dev": true, "hasInstallScript": true, @@ -7077,7 +6227,7 @@ }, "node_modules/proxy-addr": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "resolved": "https://mirrors.tencent.com/npm/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dev": true, "license": "MIT", @@ -7089,77 +6239,6 @@ "node": ">= 0.10" } }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-agent": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-8.0.1.tgz", - "integrity": "sha512-kccqGBqHZXR8onQhY/ganJjoO8QIKKRiFBhPOzbTZK16attzSZ/0XSmp9H7jrRxPKHjhGyx1q32lMPrJ3uLFgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4", - "http-proxy-agent": "9.0.0", - "https-proxy-agent": "9.0.0", - "lru-cache": "^7.14.1", - "pac-proxy-agent": "9.0.1", - "proxy-from-env": "^2.0.0", - "socks-proxy-agent": "10.0.0" - }, - "engines": { - "node": ">= 20" - } - }, - "node_modules/proxy-agent/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/proxy-from-env": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", - "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", - "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/qrcode": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", @@ -7275,7 +6354,7 @@ }, "node_modules/qs": { "version": "6.16.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/qs/-/qs-6.16.0.tgz", "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", "dev": true, "dependencies": { @@ -7290,18 +6369,17 @@ } }, "node_modules/quickjs-wasi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/quickjs-wasi/-/quickjs-wasi-2.2.0.tgz", - "integrity": "sha512-zQxXmQMrEoD3S+jQdYsloq4qAuaxKFHZj6hHqOYGwB2iQZH+q9e/lf5zQPXCKOk0WJuAjzRFbO4KwHIp2D05Iw==", - "dev": true, - "license": "MIT", - "peer": true + "version": "3.5.0", + "resolved": "https://mirrors.tencent.com/npm/quickjs-wasi/-/quickjs-wasi-3.5.0.tgz", + "integrity": "sha512-/4LKs62eqqqQyr0uVEgSvB3QeOlIpM0Wc4XPgomOfucVurDWssH2eNfDS0Y4NjQoIzoD8jVO7qWvR5drkgnRVg==", + "dev": true }, "node_modules/range-parser": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.3.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/range-parser/-/range-parser-1.3.0.tgz", "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" }, @@ -7310,9 +6388,22 @@ "url": "https://opencollective.com/express" } }, + "node_modules/rastermill": { + "version": "0.3.2", + "resolved": "https://mirrors.tencent.com/npm/rastermill/-/rastermill-0.3.2.tgz", + "integrity": "sha512-Qr4Q+PKsAyAPn4sHwY+hJ2P7rv+WJ4HZ8X+KjwVmm0tOpkb1IrtCb7sbwDZ8iJLUgiYafhmG4VHwo7Pjej0pgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@silvia-odwyer/photon-node": "0.3.4" + }, + "engines": { + "node": ">=22" + } + }, "node_modules/raw-body": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/raw-body/-/raw-body-3.0.2.tgz", "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", @@ -7328,9 +6419,10 @@ }, "node_modules/readable-stream": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "resolved": "https://mirrors.tencent.com/npm/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7343,7 +6435,7 @@ }, "node_modules/readable-stream/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "license": "MIT" @@ -7373,9 +6465,10 @@ }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7389,7 +6482,7 @@ }, "node_modules/retry": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, "engines": { @@ -7444,10 +6537,9 @@ }, "node_modules/router": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/router/-/router-2.2.0.tgz", "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", "dev": true, - "license": "MIT", "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", @@ -7502,7 +6594,7 @@ }, "node_modules/send": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/send/-/send-1.2.1.tgz", "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", "dev": true, "license": "MIT", @@ -7527,25 +6619,9 @@ "url": "https://opencollective.com/express" } }, - "node_modules/serialize-error": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", - "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/serve-static": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/serve-static/-/serve-static-2.2.1.tgz", "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", "dev": true, "license": "MIT", @@ -7571,16 +6647,16 @@ }, "node_modules/setimmediate": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "resolved": "https://mirrors.tencent.com/npm/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/shebang-command": { "version": "2.0.0", @@ -7607,7 +6683,7 @@ }, "node_modules/side-channel": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/side-channel/-/side-channel-1.1.1.tgz", "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "dev": true, "license": "MIT", @@ -7627,7 +6703,7 @@ }, "node_modules/side-channel-list": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/side-channel-list/-/side-channel-list-1.0.1.tgz", "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", @@ -7644,7 +6720,7 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "dependencies": { @@ -7662,7 +6738,7 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", @@ -7688,10 +6764,17 @@ "license": "ISC" }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "version": "4.1.0", + "resolved": "https://mirrors.tencent.com/npm/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/silk-wasm": { "version": "3.7.1", @@ -7705,55 +6788,16 @@ }, "node_modules/sisteransi": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "resolved": "https://mirrors.tencent.com/npm/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.10", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz", - "integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^10.1.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-10.0.0.tgz", - "integrity": "sha512-pyp2YR3mNxAMu0mGLtzs4g7O3uT4/9sQOLAKcViAkaS9fJWkud7nmaf6ZREFqQEi24IPkBcjfHjXhPTUWjo3uA==", - "dev": true, - "dependencies": { - "agent-base": "9.0.0", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 20" - } + "dev": true }, "node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -7770,9 +6814,10 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "resolved": "https://mirrors.tencent.com/npm/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -7870,12 +6915,22 @@ "dev": true, "license": "MIT" }, + "node_modules/standardwebhooks": { + "version": "1.1.1", + "resolved": "https://mirrors.tencent.com/npm/standardwebhooks/-/standardwebhooks-1.1.1.tgz", + "integrity": "sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/statuses": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/statuses/-/statuses-2.0.2.tgz", "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -7889,7 +6944,7 @@ }, "node_modules/string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, "dependencies": { @@ -7898,7 +6953,7 @@ }, "node_modules/string_decoder/node_modules/safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true, "license": "MIT" @@ -8011,6 +7066,18 @@ "node": ">=8" } }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://mirrors.tencent.com/npm/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/strip-literal": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", @@ -8032,7 +7099,7 @@ }, "node_modules/strtok3": { "version": "10.3.5", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-10.3.5.tgz", + "resolved": "https://mirrors.tencent.com/npm/strtok3/-/strtok3-10.3.5.tgz", "integrity": "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==", "dev": true, "license": "MIT", @@ -8061,11 +7128,10 @@ } }, "node_modules/tar": { - "version": "7.5.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz", - "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", + "version": "7.5.22", + "resolved": "https://mirrors.tencent.com/npm/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", "dev": true, - "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", @@ -8170,28 +7236,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -8255,20 +7299,18 @@ }, "node_modules/toidentifier": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/token-types": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-6.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/token-types/-/token-types-6.1.2.tgz", "integrity": "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==", "dev": true, - "license": "MIT", "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", @@ -8282,23 +7324,6 @@ "url": "https://github.com/sponsors/Borewit" } }, - "node_modules/tokenjuice": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/tokenjuice/-/tokenjuice-0.7.0.tgz", - "integrity": "sha512-RZIyFmzztf/8V4q1cUS5L+q8UISMSfsjzh4UoWVxQbE7/zX91SfNmHpNqopqyB4oc5hwH4XqC9O/yakVzJCu8g==", - "dev": true, - "license": "MIT", - "bin": { - "tokenjuice": "dist/cli/main.js" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/vincentkoc" - } - }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -8328,22 +7353,22 @@ }, "node_modules/ts-algebra": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/ts-algebra/-/ts-algebra-2.0.0.tgz", "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", "dev": true, "license": "MIT" }, "node_modules/tslib": { "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "resolved": "https://mirrors.tencent.com/npm/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, "node_modules/tslog": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/tslog/-/tslog-4.10.2.tgz", - "integrity": "sha512-XuELoRpMR+sq8fuWwX7P0bcj+PRNiicOKDEb3fGNURhxWVyykCi9BNq7c4uVz7h7P0sj8qgBsr5SWS6yBClq3g==", + "version": "4.11.0", + "resolved": "https://mirrors.tencent.com/npm/tslog/-/tslog-4.11.0.tgz", + "integrity": "sha512-gBe0FTKkRpOv3DenGipjQWQe073jNd1cOLj3nYfVM0/NP29sQzAIx6kfyfTTsQOiWMC+B+tSr289lNXtu7HCmQ==", "dev": true, "license": "MIT", "engines": { @@ -8353,24 +7378,11 @@ "url": "https://github.com/fullstack-build/tslog?sponsor=1" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/type-is/-/type-is-2.1.0.tgz", "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "dev": true, - "license": "MIT", "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", @@ -8386,9 +7398,10 @@ }, "node_modules/type-is/node_modules/content-type": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.1.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/content-type/-/content-type-2.1.0.tgz", "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -8398,9 +7411,9 @@ } }, "node_modules/typebox": { - "version": "1.1.38", - "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.1.38.tgz", - "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==", + "version": "1.3.16", + "resolved": "https://mirrors.tencent.com/npm/typebox/-/typebox-1.3.16.tgz", + "integrity": "sha512-Jac8dgnin+g2p1w1v9sk92Wvp49ZqsmSgNhrXDK+RqrovsjiORMZvYZ8t8id9b9XQp6LMfaAwnIRSHGsM+3FMw==", "dev": true, "license": "MIT" }, @@ -8418,23 +7431,16 @@ "node": ">=14.17" } }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true, - "license": "MIT" - }, "node_modules/uhyphen": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/uhyphen/-/uhyphen-0.2.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/uhyphen/-/uhyphen-0.2.0.tgz", "integrity": "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==", "dev": true, "license": "ISC" }, "node_modules/uint8array-extras": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/uint8array-extras/-/uint8array-extras-1.5.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/uint8array-extras/-/uint8array-extras-1.5.0.tgz", "integrity": "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==", "dev": true, "license": "MIT", @@ -8446,10 +7452,11 @@ } }, "node_modules/undici": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.2.0.tgz", - "integrity": "sha512-Z+4Hx9GE26Lh9Upwfnc8C7SsrpBPGaM/Gm6kMFtiG7c+5IvQKlXi/t+9x9DrrCh29cww5TSP9YdVaBcnLDs5fQ==", + "version": "8.10.0", + "resolved": "https://mirrors.tencent.com/npm/undici/-/undici-8.10.0.tgz", + "integrity": "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=22.19.0" } @@ -8461,9 +7468,22 @@ "dev": true, "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://mirrors.tencent.com/npm/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "license": "MIT", @@ -8473,31 +7493,16 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true, "license": "MIT" }, - "node_modules/uuid": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.2.tgz", - "integrity": "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist-node/bin/uuid" - } - }, "node_modules/vary": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8507,7 +7512,6 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", "dev": true, - "peer": true, "dependencies": { "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", @@ -8606,7 +7610,6 @@ "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.7", @@ -8704,33 +7707,9 @@ "node": ">= 16" } }, - "node_modules/web-push/node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/web-push/node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, "node_modules/web-streams-polyfill": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "resolved": "https://mirrors.tencent.com/npm/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "dev": true, "license": "MIT", @@ -8739,9 +7718,9 @@ } }, "node_modules/web-tree-sitter": { - "version": "0.26.8", - "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.26.8.tgz", - "integrity": "sha512-4sUwi7ZyOrIk5KLgYLkc2A/F0LFMQnBhfb+2Cdl7ik4ePJ6JD+fk4ofI2sA5eGawBKBaK4Vntt7Ww5KcEsay4A==", + "version": "0.26.12", + "resolved": "https://mirrors.tencent.com/npm/web-tree-sitter/-/web-tree-sitter-0.26.12.tgz", + "integrity": "sha512-fvqTNZQBGUgUgfP0mHw+iHf9Yf6bRQrp0A3pSf2v/hSKxkT1beCoIWoLVmlPL7O6dmySfSb/t1aJoJvrgTRStw==", "dev": true, "license": "MIT" }, @@ -8776,6 +7755,22 @@ "node": ">= 8" } }, + "node_modules/which-command": { + "version": "0.1.0", + "resolved": "https://mirrors.tencent.com/npm/which-command/-/which-command-0.1.0.tgz", + "integrity": "sha512-XZyoF5/5hZtXitIwzrU4NKK+Wtbb9aB9CezUEw2Q0wlYK8NUYQxC1rRXgNueYLtBAJwXIb+/tFVk4dozciNJMA==", + "dev": true, + "license": "MIT", + "bin": { + "which-command": "cli.js" + }, + "engines": { + "node": ">=22" + }, + "funding": { + "url": "https://github.com/sindresorhus/which-command?sponsor=1" + } + }, "node_modules/which-module": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", @@ -8878,15 +7873,15 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, "license": "ISC" }, "node_modules/ws": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", - "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "version": "8.21.3", + "resolved": "https://mirrors.tencent.com/npm/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "dev": true, "engines": { "node": ">=10.0.0" @@ -8915,9 +7910,10 @@ }, "node_modules/yallist": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "resolved": "https://mirrors.tencent.com/npm/yallist/-/yallist-5.0.0.tgz", "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": ">=18" } @@ -8937,42 +7933,30 @@ "url": "https://github.com/sponsors/eemeli" } }, - "node_modules/yargs": { - "version": "16.2.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.2.tgz", - "integrity": "sha512-Nt9ZJjXTv5R8MHbqby/wXQ6Gi0Bb3TcYZkR1bzuL4yB2OxWPkXknz513gEF0GoA6tn00UpbPvERW8rzCuWCA6w==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://mirrors.tencent.com/npm/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "node_modules/yoctocolors": { + "version": "2.2.0", + "resolved": "https://mirrors.tencent.com/npm/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", "dev": true, "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/zod": { @@ -8980,16 +7964,16 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } }, "node_modules/zod-to-json-schema": { "version": "3.25.2", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "resolved": "https://mirrors.tencent.com/npm/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", "dev": true, + "license": "ISC", "peerDependencies": { "zod": "^3.25.28 || ^4" } diff --git a/package.json b/package.json index dfb8244..85cb14c 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "prepublishOnly": "npm run typecheck && npm run build" }, "engines": { - "node": ">=22" + "node": ">=22.13.0" }, "dependencies": { "qrcode-terminal": "0.12.0", @@ -41,7 +41,7 @@ }, "devDependencies": { "@vitest/coverage-v8": "^3.1.0", - "openclaw": "2026.5.12", + "openclaw": "2026.8.1", "oxfmt": "0.60.0", "oxlint": "1.80.0", "silk-wasm": "^3.7.1", diff --git a/src/api/api.test.ts b/src/api/api.test.ts index a12408d..de1fe01 100644 --- a/src/api/api.test.ts +++ b/src/api/api.test.ts @@ -37,6 +37,7 @@ import { sanitizeBotAgent, readPackageJsonFromDir, classifyFetchError, + parseWeixinApiJson, } from "./api.js"; function mockResponse(body: object | string, status = 200, ok = true): Response { @@ -187,7 +188,14 @@ describe("sendMessage", () => { } as Response); await expect( sendMessage({ baseUrl: "https://api.example.com/", body: { msg: { to_user_id: "u" } } }), - ).resolves.toBeUndefined(); + ).resolves.toEqual({}); + }); + + it("returns a lossless server message ID", async () => { + mockFetch.mockResolvedValueOnce(mockResponse('{"ret":0,"message_id":18446744073709551615}')); + await expect( + sendMessage({ baseUrl: "https://api.example.com/", body: { msg: { to_user_id: "u" } } }), + ).resolves.toMatchObject({ message_id: "18446744073709551615" }); }); it("throws on non-ok response", async () => { @@ -196,6 +204,54 @@ describe("sendMessage", () => { sendMessage({ baseUrl: "https://api.example.com/", body: { msg: {} } }), ).rejects.toThrow("sendMessage 403"); }); + + it("throws on a successful HTTP response with a non-zero API ret", async () => { + mockFetch.mockResolvedValueOnce(mockResponse({ ret: 1 })); + await expect( + sendMessage({ baseUrl: "https://api.example.com/", body: { msg: {} } }), + ).rejects.toThrow("sendMessage ret=1 errmsg=(none)"); + }); +}); + +describe("parseWeixinApiJson", () => { + it("preserves all known uint64 message ID fields as strings", () => { + const parsed = parseWeixinApiJson<{ + message_id: string; + nested: { msg_id: string; ref: { svr_id: string } }; + }>( + '{"message_id":18446744073709551615,"nested":{"msg_id" : 9007199254740993,"ref":{"svr_id": 123}}}', + ); + expect(parsed).toEqual({ + message_id: "18446744073709551615", + nested: { msg_id: "9007199254740993", ref: { svr_id: "123" } }, + }); + }); + + it("does not rewrite matching text inside JSON strings", () => { + const raw = '{"text":"\\\"message_id\\\":18446744073709551615","message_id":"7"}'; + expect(parseWeixinApiJson<{ text: string; message_id: string }>(raw)).toEqual({ + text: '"message_id":18446744073709551615', + message_id: "7", + }); + }); + + it("leaves non-ID keys and non-numeric ID values unchanged", () => { + expect( + parseWeixinApiJson( + '{ "other": 9007199254740993, "message_id": null, "msg_id": "already-string" }', + ), + ).toEqual({ + other: 9007199254740992, + message_id: null, + msg_id: "already-string", + }); + }); + + it("handles negative numeric IDs without losing precision", () => { + expect(parseWeixinApiJson<{ svr_id: string }>('{"svr_id" : -9007199254740993}')).toEqual({ + svr_id: "-9007199254740993", + }); + }); }); describe("getConfig", () => { diff --git a/src/api/api.ts b/src/api/api.ts index d59de2b..5febfea 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -467,7 +467,7 @@ export async function getUpdates( label: "getUpdates", abortSignal: params.abortSignal, }); - const resp: GetUpdatesResp = JSON.parse(rawText); + const resp = parseWeixinApiJson(rawText); return resp; } catch (err) { // Long-poll timeout or external abort are both normal control-flow exits. @@ -515,10 +515,71 @@ export async function getUploadUrl( return resp; } -/** Send a single message downstream. */ +const LOSSLESS_ID_FIELDS = new Set(["message_id", "msg_id", "svr_id"]); + +/** + * Quote uint64 message identifiers before JSON.parse sees them. This scanner + * only rewrites actual object properties, never matching text inside JSON strings. + */ +export function parseWeixinApiJson(rawText: string): T { + let output = ""; + let index = 0; + while (index < rawText.length) { + if (rawText[index] !== '"') { + output += rawText[index++]; + continue; + } + + const stringStart = index; + index++; + let escaped = false; + while (index < rawText.length) { + const char = rawText[index++]; + if (escaped) { + escaped = false; + } else if (char === "\\") { + escaped = true; + } else if (char === '"') { + break; + } + } + const stringToken = rawText.slice(stringStart, index); + output += stringToken; + + let cursor = index; + while (/\s/.test(rawText[cursor] ?? "")) cursor++; + if (rawText[cursor] !== ":") continue; + + let key: unknown; + try { + key = JSON.parse(stringToken); + } catch { + continue; + } + if (typeof key !== "string" || !LOSSLESS_ID_FIELDS.has(key)) continue; + + output += rawText.slice(index, cursor + 1); + cursor++; + while (/\s/.test(rawText[cursor] ?? "")) { + output += rawText[cursor++]; + } + const numberStart = cursor; + if (rawText[cursor] === "-") cursor++; + while (/\d/.test(rawText[cursor] ?? "")) cursor++; + if (cursor > numberStart && !(cursor === numberStart + 1 && rawText[numberStart] === "-")) { + output += `"${rawText.slice(numberStart, cursor)}"`; + index = cursor; + } else { + index = numberStart; + } + } + return JSON.parse(output) as T; +} + +/** Send a single message downstream and return the server-assigned message ID. */ export async function sendMessage( params: WeixinApiOptions & { body: SendMessageReq }, -): Promise { +): Promise { const rawText = await apiPostFetch({ baseUrl: params.baseUrl, endpoint: "ilink/bot/sendmessage", @@ -527,10 +588,11 @@ export async function sendMessage( timeoutMs: params.timeoutMs ?? DEFAULT_API_TIMEOUT_MS, label: "sendMessage", }); - const resp: SendMessageResp = JSON.parse(rawText); + const resp = parseWeixinApiJson(rawText); if (resp.ret && resp.ret !== 0) { throw new Error(`sendMessage ret=${resp.ret} errmsg=${resp.errmsg ?? "(none)"}`); } + return resp; } /** Fetch bot config (includes typing_ticket) for a given user. */ diff --git a/src/api/types.ts b/src/api/types.ts index f63656d..276e845 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -147,6 +147,18 @@ export interface VideoItem { export interface RefMessage { message_item?: MessageItem; title?: string; // 摘要 + /** Server message ID used when newer clients omit the quoted content. */ + svr_id?: string; + /** Optional metadata describing a selected substring of the quoted message. */ + partial_text?: PartialText; +} + +export interface PartialText { + start: string; + end: string; + startindex: number; + endindex: number; + quotemd5: string; } export interface ToolCallStartItem { @@ -179,7 +191,8 @@ export interface MessageItem { /** Unified message (proto: WeixinMessage). Replaces the old split Message + MessageContent + FullMessage. */ export interface WeixinMessage { seq?: number; - message_id?: number; + /** uint64 on the wire; parsed losslessly as a string. */ + message_id?: string; from_user_id?: string; to_user_id?: string; client_id?: string; @@ -224,6 +237,8 @@ export interface SendMessageReq { } export interface SendMessageResp { + /** uint64 on the wire; parsed losslessly as a string. */ + message_id?: string; ret?: number; errmsg?: string; } diff --git a/src/auth/account-index.test.ts b/src/auth/account-index.test.ts index 7e79027..5d37ba6 100644 --- a/src/auth/account-index.test.ts +++ b/src/auth/account-index.test.ts @@ -3,6 +3,8 @@ import fs from "node:fs"; import path from "node:path"; import os from "node:os"; +import * as accounts from "./accounts.js"; + vi.mock("../util/logger.js", () => ({ logger: { info: vi.fn(), @@ -25,8 +27,7 @@ afterEach(() => { }); async function loadModule() { - vi.resetModules(); - return await import("./accounts.js"); + return accounts; } describe("listIndexedWeixinAccountIds", () => { diff --git a/src/auth/account-store.test.ts b/src/auth/account-store.test.ts index 4a3f21d..d355a6d 100644 --- a/src/auth/account-store.test.ts +++ b/src/auth/account-store.test.ts @@ -3,6 +3,8 @@ import fs from "node:fs"; import path from "node:path"; import os from "node:os"; +import * as accounts from "./accounts.js"; + // Mock dependencies before importing module under test vi.mock("../util/logger.js", () => ({ logger: { @@ -26,11 +28,10 @@ afterEach(() => { fs.rmSync(tmpDir, { recursive: true, force: true }); }); -// Dynamic import so mocks are applied and env is set before module init +// The module reads OPENCLAW_STATE_DIR when its functions are called, so a +// static import avoids repeated cold starts while keeping each test isolated. async function loadModule() { - // Clear module cache to pick up new env - vi.resetModules(); - return await import("./accounts.js"); + return accounts; } describe("loadWeixinAccount", () => { diff --git a/src/auth/accounts.ts b/src/auth/accounts.ts index 43d613e..dbfa878 100644 --- a/src/auth/accounts.ts +++ b/src/auth/accounts.ts @@ -5,6 +5,7 @@ import { normalizeAccountId } from "openclaw/plugin-sdk/account-id"; import type { OpenClawConfig } from "openclaw/plugin-sdk/core"; import { resolveStateDir } from "../storage/state-dir.js"; +import { deleteQuoteCacheForAccount } from "../messaging/quote-store.js"; import { resolveFrameworkAllowFromPath } from "./pairing.js"; import { logger } from "../util/logger.js"; @@ -224,6 +225,7 @@ export function saveWeixinAccount( * - credentials/openclaw-weixin-{accountId}-allowFrom.json (authorized users) */ export function clearWeixinAccount(accountId: string): void { + deleteQuoteCacheForAccount(accountId); const dir = resolveAccountsDir(); const accountFiles = [ `${accountId}.json`, diff --git a/src/channel.ts b/src/channel.ts index 87917c4..1899793 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -23,6 +23,7 @@ import { restoreContextTokens, clearContextTokensForAccount, } from "./messaging/inbound.js"; +import { deactivateQuoteStoreAccount, initializeQuoteStore } from "./messaging/quote-store.js"; import { logger } from "./util/logger.js"; import { DEFAULT_ILINK_BOT_TYPE, @@ -158,6 +159,7 @@ async function sendWeixinOutbound(params: { baseUrl: account.baseUrl, token: account.token, contextToken: params.contextToken, + accountId: account.accountId, }, }); emitWeixinMessageSent({ @@ -200,6 +202,27 @@ export const weixinPlugin: ChannelPlugin = { default: true, description: "Send structured tool-call progress messages.", }, + quoteCache: { + type: "object", + additionalProperties: false, + description: "Persist message content locally so ID-only Weixin quotes can be resolved.", + properties: { + enabled: { type: "boolean", default: true }, + retentionDays: { type: "number", default: 30, minimum: 0.01 }, + maxMessagesPerAccount: { type: "integer", default: 10000, minimum: 1 }, + mediaRetentionDays: { type: "number", default: 7, minimum: 0.01 }, + maxMediaBytesPerAccount: { + type: "integer", + default: 268435456, + minimum: 1, + }, + maxSingleMediaBytes: { + type: "integer", + default: 26214400, + minimum: 1, + }, + }, + }, }, }, }, @@ -298,7 +321,12 @@ export const weixinPlugin: ChannelPlugin = { filePath, to: ctx.to, text, - opts: { baseUrl: account.baseUrl, token: account.token, contextToken }, + opts: { + baseUrl: account.baseUrl, + token: account.token, + contextToken, + accountId: account.accountId, + }, cdnBaseUrl: account.cdnBaseUrl, }); emitWeixinMessageSent({ @@ -329,6 +357,7 @@ export const weixinPlugin: ChannelPlugin = { baseUrl: account.baseUrl, token: account.token, contextToken, + accountId: account.accountId, }, }); emitWeixinMessageSent({ @@ -483,6 +512,8 @@ export const weixinPlugin: ChannelPlugin = { throw new Error("weixin not configured: missing token"); } + await initializeQuoteStore(ctx.cfg, account.accountId); + ctx.log?.info?.(`[${account.accountId}] starting weixin provider (${DEFAULT_BASE_URL})`); try { @@ -527,6 +558,7 @@ export const weixinPlugin: ChannelPlugin = { stopAccount: async (ctx) => { const account = ctx.account; const aLog = logger.withAccount(account.accountId); + deactivateQuoteStoreAccount(account.accountId); if (!account.configured || !account.token?.trim()) { aLog.debug(`gateway.stopAccount: skip notifyStop (not configured or no token)`); return; diff --git a/src/config/config-schema.test.ts b/src/config/config-schema.test.ts index f65397a..56bcade 100644 --- a/src/config/config-schema.test.ts +++ b/src/config/config-schema.test.ts @@ -7,6 +7,14 @@ describe("WeixinConfigSchema", () => { expect(result.baseUrl).toBe("https://ilinkai.weixin.qq.com"); expect(result.cdnBaseUrl).toBe("https://novac2c.cdn.weixin.qq.com/c2c"); expect(result.replyProgressMessages).toBe(true); + expect(result.quoteCache).toEqual({ + enabled: true, + retentionDays: 30, + maxMessagesPerAccount: 10_000, + mediaRetentionDays: 7, + maxMediaBytesPerAccount: 256 * 1024 * 1024, + maxSingleMediaBytes: 25 * 1024 * 1024, + }); }); it("accepts custom baseUrl and cdnBaseUrl", () => { @@ -34,6 +42,12 @@ describe("WeixinConfigSchema", () => { expect(result.replyProgressMessages).toBe(false); }); + it("accepts disabling quote caching for hosts without SQLite", () => { + const result = WeixinConfigSchema.parse({ quoteCache: { enabled: false } }); + expect(result.quoteCache.enabled).toBe(false); + expect(result.quoteCache.retentionDays).toBe(30); + }); + it("accepts accounts map", () => { const result = WeixinConfigSchema.parse({ accounts: { diff --git a/src/config/config-schema.ts b/src/config/config-schema.ts index 4d152cc..da256ec 100644 --- a/src/config/config-schema.ts +++ b/src/config/config-schema.ts @@ -14,10 +14,35 @@ const weixinAccountSchema = z.object({ routeTag: z.number().optional(), }); +const quoteCacheSchema = z.object({ + enabled: z.boolean().default(true), + retentionDays: z.number().positive().default(30), + maxMessagesPerAccount: z.number().int().positive().default(10_000), + mediaRetentionDays: z.number().positive().default(7), + maxMediaBytesPerAccount: z + .number() + .int() + .positive() + .default(256 * 1024 * 1024), + maxSingleMediaBytes: z + .number() + .int() + .positive() + .default(25 * 1024 * 1024), +}); + /** Top-level weixin config schema (token is stored in credentials file, not config). */ export const WeixinConfigSchema = weixinAccountSchema.extend({ accounts: z.record(z.string(), weixinAccountSchema).optional(), replyProgressMessages: z.boolean().default(true), + quoteCache: quoteCacheSchema.default({ + enabled: true, + retentionDays: 30, + maxMessagesPerAccount: 10_000, + mediaRetentionDays: 7, + maxMediaBytesPerAccount: 256 * 1024 * 1024, + maxSingleMediaBytes: 25 * 1024 * 1024, + }), /** ISO 8601; bumped on each successful login to refresh gateway config from disk. */ channelConfigUpdatedAt: z.string().optional(), }); diff --git a/src/media/media-download.ts b/src/media/media-download.ts index 5a2fda7..3f66d02 100644 --- a/src/media/media-download.ts +++ b/src/media/media-download.ts @@ -26,12 +26,15 @@ export async function downloadMediaFromItem( deps: { cdnBaseUrl: string; saveMedia: SaveMediaFn; + /** OpenClaw media-store subdirectory; defaults to the transient inbound bucket. */ + mediaSubdir?: string; log: (msg: string) => void; errLog: (msg: string) => void; label: string; }, ): Promise { const { cdnBaseUrl, saveMedia, log, errLog, label } = deps; + const mediaSubdir = deps.mediaSubdir ?? "inbound"; const result: WeixinInboundMediaOpts = {}; if (item.type === MessageItemType.IMAGE) { @@ -58,7 +61,7 @@ export async function downloadMediaFromItem( `${label} image-plain`, img.media.full_url, ); - const saved = await saveMedia(buf, undefined, "inbound", WEIXIN_MEDIA_MAX_BYTES); + const saved = await saveMedia(buf, undefined, mediaSubdir, WEIXIN_MEDIA_MAX_BYTES); result.decryptedPicPath = saved.path; logger.debug(`${label} image saved: ${saved.path}`); } catch (err) { @@ -80,12 +83,12 @@ export async function downloadMediaFromItem( logger.debug(`${label} voice: decrypted ${silkBuf.length} bytes, attempting silk transcode`); const wavBuf = await silkToWav(silkBuf); if (wavBuf) { - const saved = await saveMedia(wavBuf, "audio/wav", "inbound", WEIXIN_MEDIA_MAX_BYTES); + const saved = await saveMedia(wavBuf, "audio/wav", mediaSubdir, WEIXIN_MEDIA_MAX_BYTES); result.decryptedVoicePath = saved.path; result.voiceMediaType = "audio/wav"; logger.debug(`${label} voice: saved WAV to ${saved.path}`); } else { - const saved = await saveMedia(silkBuf, "audio/silk", "inbound", WEIXIN_MEDIA_MAX_BYTES); + const saved = await saveMedia(silkBuf, "audio/silk", mediaSubdir, WEIXIN_MEDIA_MAX_BYTES); result.decryptedVoicePath = saved.path; result.voiceMediaType = "audio/silk"; logger.debug(`${label} voice: silk transcode unavailable, saved raw SILK to ${saved.path}`); @@ -113,7 +116,7 @@ export async function downloadMediaFromItem( const saved = await saveMedia( buf, mime, - "inbound", + mediaSubdir, WEIXIN_MEDIA_MAX_BYTES, fileItem.file_name ?? undefined, ); @@ -139,7 +142,7 @@ export async function downloadMediaFromItem( `${label} video`, videoItem.media.full_url, ); - const saved = await saveMedia(buf, "video/mp4", "inbound", WEIXIN_MEDIA_MAX_BYTES); + const saved = await saveMedia(buf, "video/mp4", mediaSubdir, WEIXIN_MEDIA_MAX_BYTES); result.decryptedVideoPath = saved.path; logger.debug(`${label} video: saved to ${saved.path}`); } catch (err) { diff --git a/src/messaging/error-notice.ts b/src/messaging/error-notice.ts index a2d299d..0532832 100644 --- a/src/messaging/error-notice.ts +++ b/src/messaging/error-notice.ts @@ -13,6 +13,7 @@ export async function sendWeixinErrorNotice(params: { baseUrl: string; token?: string; runId?: string; + accountId?: string; errLog: (m: string) => void; }): Promise { if (!params.contextToken) { @@ -28,6 +29,7 @@ export async function sendWeixinErrorNotice(params: { baseUrl: params.baseUrl, token: params.token, contextToken: params.contextToken, + accountId: params.accountId, ...(params.runId ? { runId: params.runId } : {}), }, }); diff --git a/src/messaging/inbound.test.ts b/src/messaging/inbound.test.ts index 927fd9b..91918b5 100644 --- a/src/messaging/inbound.test.ts +++ b/src/messaging/inbound.test.ts @@ -1,8 +1,14 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + import { describe, it, expect, vi, beforeEach } from "vitest"; import { + getContextTokenFromMsgContext, + getWeixinMessageId, isMediaItem, + resolveStoredQuoteContext, weixinMessageToMsgContext, - getContextTokenFromMsgContext, } from "./inbound.js"; import type { WeixinMsgContext } from "./inbound.js"; import { MessageItemType } from "../api/types.js"; @@ -51,6 +57,17 @@ describe("isMediaItem", () => { }); }); +describe("getMediaLabel", () => { + it("labels every supported media kind", async () => { + const { getMediaLabel } = await import("./inbound.js"); + expect(getMediaLabel(MessageItemType.IMAGE)).toBe("[图片]"); + expect(getMediaLabel(MessageItemType.VIDEO)).toBe("[视频]"); + expect(getMediaLabel(MessageItemType.FILE)).toBe("[文件]"); + expect(getMediaLabel(MessageItemType.VOICE)).toBe("[语音]"); + expect(getMediaLabel(MessageItemType.TEXT)).toBe(""); + }); +}); + describe("weixinMessageToMsgContext", () => { beforeEach(() => { vi.spyOn(Date, "now").mockReturnValue(1700000000000); @@ -144,6 +161,17 @@ describe("weixinMessageToMsgContext", () => { expect(ctx.MediaType).toBe("audio/wav"); }); + it("uses transcribed voice text as the body", () => { + const ctx = weixinMessageToMsgContext( + { + from_user_id: "u", + item_list: [{ type: MessageItemType.VOICE, voice_item: { text: "voice transcript" } }], + }, + "acc", + ); + expect(ctx.Body).toBe("voice transcript"); + }); + it("prioritizes pic > video > file > voice", () => { const ctx = weixinMessageToMsgContext(baseMsg, "acc", { decryptedPicPath: "/tmp/pic.png", @@ -155,6 +183,17 @@ describe("weixinMessageToMsgContext", () => { expect(ctx.MediaType).toBe("image/*"); }); + it("keeps downloaded inline-quote media out of the current message attachment", () => { + const ctx = weixinMessageToMsgContext(baseMsg, "acc", { + decryptedPicPath: "/tmp/quoted.png", + referencedMedia: true, + }); + expect(ctx.MediaPath).toBeUndefined(); + expect(ctx.MediaType).toBeUndefined(); + expect(ctx.MediaPaths).toEqual(["/tmp/quoted.png"]); + expect(ctx.MediaTypes).toEqual(["image/*"]); + }); + it("builds quoted context from ref_msg title", () => { const msg: WeixinMessage = { from_user_id: "u", @@ -167,7 +206,9 @@ describe("weixinMessageToMsgContext", () => { ], }; const ctx = weixinMessageToMsgContext(msg, "acc"); - expect(ctx.Body).toBe("[引用: original title]\nreply"); + expect(ctx.Body).toBe("reply"); + expect(ctx.ReplyToBody).toBe("original title"); + expect(ctx.ReplyToIsQuote).toBe(true); }); it("skips quoted context when ref_msg is a media item", () => { @@ -205,7 +246,9 @@ describe("weixinMessageToMsgContext", () => { ], }; const ctx = weixinMessageToMsgContext(msg, "acc"); - expect(ctx.Body).toBe("[引用: Author | original text]\nmy reply"); + expect(ctx.Body).toBe("my reply"); + expect(ctx.ReplyToBody).toBe("Author | original text"); + expect(ctx.ReplyToIsQuote).toBe(true); }); it("builds quoted context with only message_item (no title)", () => { @@ -225,7 +268,8 @@ describe("weixinMessageToMsgContext", () => { ], }; const ctx = weixinMessageToMsgContext(msg, "acc"); - expect(ctx.Body).toBe("[引用: quoted]\nreply"); + expect(ctx.Body).toBe("reply"); + expect(ctx.ReplyToBody).toBe("quoted"); }); it("returns text when ref_msg has no extractable content", () => { @@ -243,13 +287,262 @@ describe("weixinMessageToMsgContext", () => { expect(ctx.Body).toBe("reply"); }); - it("returns empty body when item_list has only non-text items", () => { + it("uses a stable label when item_list has only a media item", () => { const msg: WeixinMessage = { from_user_id: "u", item_list: [{ type: MessageItemType.IMAGE }], }; const ctx = weixinMessageToMsgContext(msg, "acc"); - expect(ctx.Body).toBe(""); + expect(ctx.Body).toBe("[图片]"); + }); + + it("keeps the provider uint64 ID separately from the generated MessageSid", () => { + const ctx = weixinMessageToMsgContext( + { ...baseMsg, message_id: "18446744073709551615" }, + "acc", + ); + expect(ctx.MessageSidFull).toBe("18446744073709551615"); + expect(ctx.MessageSid).not.toBe(ctx.MessageSidFull); + }); +}); + +describe("stored quote resolution", () => { + const quotedMessage = ( + partial_text?: NonNullable["partial_text"]>, + ): WeixinMessage => ({ + from_user_id: "user1", + item_list: [ + { + type: MessageItemType.TEXT, + text_item: { text: "reply" }, + ref_msg: { svr_id: "9007199254740993123", ...(partial_text ? { partial_text } : {}) }, + }, + ], + }); + + it("looks up an ID-only quote in the account and conversation scope", () => { + const msg = quotedMessage(); + const ctx = weixinMessageToMsgContext(msg, "acc"); + const find = vi.fn(() => ({ + accountId: "acc", + conversationId: "user1", + messageId: "9007199254740993123", + direction: "inbound" as const, + body: "original text", + createdAt: Date.now(), + })); + resolveStoredQuoteContext(ctx, msg, "acc", { find }); + expect(find).toHaveBeenCalledWith("acc", "user1", "9007199254740993123"); + expect(ctx).toMatchObject({ + Body: "reply", + ReplyToId: "9007199254740993123", + ReplyToBody: "original text", + ReplyToIsQuote: true, + }); + }); + + it("marks a cache miss without modifying the current message body", () => { + const msg = quotedMessage(); + const ctx = weixinMessageToMsgContext(msg, "acc"); + resolveStoredQuoteContext(ctx, msg, "acc", { find: () => null }); + expect(ctx.Body).toBe("reply"); + expect(ctx.ReplyToBody).toBe("[引用消息内容未缓存]"); + }); + + it("resolves the legacy nested message ID", () => { + const msg: WeixinMessage = { + from_user_id: "user1", + item_list: [ + { + type: MessageItemType.TEXT, + text_item: { text: "reply" }, + ref_msg: { message_item: { type: MessageItemType.TEXT, msg_id: "legacy-id" } }, + }, + ], + }; + const ctx = weixinMessageToMsgContext(msg, "acc"); + resolveStoredQuoteContext(ctx, msg, "acc", { + find: () => ({ + accountId: "acc", + conversationId: "user1", + messageId: "legacy-id", + direction: "inbound", + body: "legacy body", + createdAt: Date.now(), + }), + }); + expect(ctx.ReplyToId).toBe("legacy-id"); + expect(ctx.ReplyToBody).toBe("legacy body"); + }); + + it("keeps complete inline quote content instead of replacing it from storage", () => { + const msg: WeixinMessage = { + from_user_id: "user1", + item_list: [ + { + type: MessageItemType.TEXT, + text_item: { text: "reply" }, + ref_msg: { + svr_id: "id", + message_item: { type: MessageItemType.TEXT, text_item: { text: "inline body" } }, + }, + }, + ], + }; + const ctx = weixinMessageToMsgContext(msg, "acc"); + const find = vi.fn(); + resolveStoredQuoteContext(ctx, msg, "acc", { find }); + expect(find).not.toHaveBeenCalled(); + expect(ctx.ReplyToBody).toBe("inline body"); + }); + + it("sets ReplyToQuoteText for a partial quote", () => { + const selected = "second abc"; + const msg = quotedMessage({ + start: "s", + end: "c", + startindex: 1, + endindex: 2, + quotemd5: "", + }); + const ctx = weixinMessageToMsgContext(msg, "acc"); + resolveStoredQuoteContext(ctx, msg, "acc", { + find: () => ({ + accountId: "acc", + conversationId: "user1", + messageId: "9007199254740993123", + direction: "inbound", + body: "start abc, second abc", + createdAt: Date.now(), + }), + }); + expect(ctx.ReplyToQuoteText).toBe(selected); + }); + + it.each([ + ["image/png", "picture.png", "[引用的图片已过期: picture.png]"], + ["video/mp4", undefined, "[引用的视频已过期]"], + ["audio/mpeg", undefined, "[引用的语音已过期]"], + ["application/pdf", "doc.pdf", "[引用的附件已过期: doc.pdf]"], + ])("describes expired managed media (%s)", (mediaMime, mediaName, expected) => { + const msg = quotedMessage(); + const ctx = weixinMessageToMsgContext(msg, "acc"); + resolveStoredQuoteContext(ctx, msg, "acc", { + find: () => ({ + accountId: "acc", + conversationId: "user1", + messageId: "9007199254740993123", + direction: "inbound", + body: "[媒体]", + mediaMime, + ...(mediaName ? { mediaName } : {}), + createdAt: Date.now(), + }), + }); + expect(ctx.ReplyToBody).toBe(expected); + }); + + it("adds an existing quoted media file alongside the current attachment", () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "weixin-inbound-quote-")); + const quotedPath = path.join(tempDir, "quoted.png"); + fs.writeFileSync(quotedPath, "image"); + try { + const msg = quotedMessage(); + const ctx = weixinMessageToMsgContext(msg, "acc", { decryptedFilePath: "/tmp/current.pdf" }); + ctx.ChannelPromptContext = ["existing channel context"]; + resolveStoredQuoteContext(ctx, msg, "acc", { + find: () => ({ + accountId: "acc", + conversationId: "user1", + messageId: "9007199254740993123", + direction: "inbound", + body: "[图片]", + mediaPath: quotedPath, + mediaMime: "image/png", + mediaName: "quoted-original.png", + createdAt: Date.now(), + }), + }); + expect(ctx.MediaPaths).toEqual(["/tmp/current.pdf", quotedPath]); + expect(ctx.MediaTypes).toEqual(["application/octet-stream", "image/png"]); + expect(ctx.media).toEqual([ + { path: "/tmp/current.pdf", contentType: "application/octet-stream" }, + { + path: quotedPath, + contentType: "image/png", + fileName: "quoted-original.png", + messageId: "9007199254740993123", + }, + ]); + expect(ctx.ChannelPromptContext).toEqual([ + "existing channel context", + [ + "Quoted attachment tool access:", + JSON.stringify({ + message_id: "9007199254740993123", + original_filename: "quoted-original.png", + managed_source_path: quotedPath, + workspace_directory: "media/inbound/", + }), + "The attachment is staged into the agent workspace under media/inbound/. " + + "If automatic extraction fails and the user asks about its contents, use the available " + + "file/PDF tools to locate it by original_filename and read it.", + ].join("\n"), + ]); + } finally { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + }); + + it("marks a referenced media path that disappeared from disk as expired", () => { + const msg = quotedMessage(); + const ctx = weixinMessageToMsgContext(msg, "acc"); + resolveStoredQuoteContext(ctx, msg, "acc", { + find: () => ({ + accountId: "acc", + conversationId: "user1", + messageId: "9007199254740993123", + direction: "inbound", + body: "[视频]", + mediaPath: "/definitely/missing/video.mp4", + mediaMime: "video/mp4", + createdAt: Date.now(), + }), + }); + expect(ctx.ReplyToBody).toBe("[引用的视频已过期]"); + }); + + it("adds a tool-access hint and falls back to the managed basename", () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "weixin-inbound-quote-hint-")); + const quotedPath = path.join(tempDir, "managed-document.pdf"); + fs.writeFileSync(quotedPath, "pdf"); + try { + const msg = quotedMessage(); + const ctx = weixinMessageToMsgContext(msg, "acc"); + resolveStoredQuoteContext(ctx, msg, "acc", { + find: () => ({ + accountId: "acc", + conversationId: "user1", + messageId: "9007199254740993123", + direction: "inbound", + body: "[文件]", + mediaPath: quotedPath, + mediaMime: "application/pdf", + createdAt: Date.now(), + }), + }); + expect(ctx.ChannelPromptContext?.[0]).toContain('"original_filename":"managed-document.pdf"'); + expect(ctx.ChannelPromptContext?.[0]).toContain('"workspace_directory":"media/inbound/"'); + } finally { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + }); +}); + +describe("getWeixinMessageId", () => { + it("prefers the top-level ID and falls back to an item ID", () => { + expect(getWeixinMessageId({ message_id: "10", item_list: [{ msg_id: "11" }] })).toBe("10"); + expect(getWeixinMessageId({ item_list: [{ msg_id: "11" }] })).toBe("11"); }); }); diff --git a/src/messaging/inbound.ts b/src/messaging/inbound.ts index cc47d4c..fea1b40 100644 --- a/src/messaging/inbound.ts +++ b/src/messaging/inbound.ts @@ -6,6 +6,9 @@ import { generateId } from "../util/random.js"; import type { WeixinMessage, MessageItem } from "../api/types.js"; import { MessageItemType } from "../api/types.js"; import { resolveStateDir } from "../storage/state-dir.js"; +import { resolvePartialQuote } from "./partial-quote.js"; +import { getQuoteStore } from "./quote-store.js"; +import type { QuoteStore } from "./quote-store.js"; // --------------------------------------------------------------------------- // Context token store (in-process cache + disk persistence) @@ -141,6 +144,8 @@ export type WeixinMsgContext = { OriginatingChannel: "openclaw-weixin"; OriginatingTo: string; MessageSid: string; + /** Provider message ID retained losslessly for transcript metadata. */ + MessageSidFull?: string; Timestamp?: number; Provider: "openclaw-weixin"; ChatType: "direct"; @@ -150,6 +155,19 @@ export type WeixinMsgContext = { MediaUrl?: string; MediaPath?: string; MediaType?: string; + MediaPaths?: string[]; + MediaTypes?: string[]; + media?: Array<{ + path?: string; + contentType?: string; + fileName?: string; + messageId?: string; + }>; + ChannelPromptContext?: string[]; + ReplyToId?: string; + ReplyToBody?: string; + ReplyToQuoteText?: string; + ReplyToIsQuote?: boolean; /** Raw message body for framework command authorization. */ CommandBody?: string; /** Whether the sender is authorized to execute slash commands. */ @@ -166,29 +184,42 @@ export function isMediaItem(item: MessageItem): boolean { ); } +export function getMediaLabel(type: number | undefined): string { + switch (type) { + case MessageItemType.IMAGE: + return "[图片]"; + case MessageItemType.VIDEO: + return "[视频]"; + case MessageItemType.FILE: + return "[文件]"; + case MessageItemType.VOICE: + return "[语音]"; + default: + return ""; + } +} + +export function getWeixinMessageId(msg: WeixinMessage): string | undefined { + const topLevel = msg.message_id?.trim(); + if (topLevel) return topLevel; + for (const item of msg.item_list ?? []) { + const itemId = item.msg_id?.trim(); + if (itemId) return itemId; + } + return undefined; +} + function bodyFromItemList(itemList?: MessageItem[]): string { if (!itemList?.length) return ""; for (const item of itemList) { if (item.type === MessageItemType.TEXT && item.text_item?.text != null) { - const text = String(item.text_item.text); - const ref = item.ref_msg; - if (!ref) return text; - // Quoted media is passed as MediaPath; only include the current text as body. - if (ref.message_item && isMediaItem(ref.message_item)) return text; - // Build quoted context from both title and message_item content. - const parts: string[] = []; - if (ref.title) parts.push(ref.title); - if (ref.message_item) { - const refBody = bodyFromItemList([ref.message_item]); - if (refBody) parts.push(refBody); - } - if (!parts.length) return text; - return `[引用: ${parts.join(" | ")}]\n${text}`; + return String(item.text_item.text); } // 语音转文字:如果语音消息有 text 字段,直接使用文字内容 if (item.type === MessageItemType.VOICE && item.voice_item?.text) { return item.voice_item.text; } + if (isMediaItem(item)) return getMediaLabel(item.type); } return ""; } @@ -206,6 +237,8 @@ export type WeixinInboundMediaOpts = { fileMediaType?: string; /** Local path to decrypted video file. */ decryptedVideoPath?: string; + /** The downloaded media belongs to an inline quoted message, not the current message. */ + referencedMedia?: boolean; }; /** @@ -235,6 +268,8 @@ export function weixinMessageToMsgContext( if (msg.context_token) { ctx.context_token = msg.context_token; } + const providerMessageId = getWeixinMessageId(msg); + if (providerMessageId) ctx.MessageSidFull = providerMessageId; if (opts?.decryptedPicPath) { ctx.MediaPath = opts.decryptedPicPath; @@ -250,9 +285,123 @@ export function weixinMessageToMsgContext( ctx.MediaType = opts.voiceMediaType ?? "audio/wav"; } + if (opts?.referencedMedia && ctx.MediaPath) { + ctx.MediaPaths = [ctx.MediaPath]; + ctx.MediaTypes = [ctx.MediaType ?? "application/octet-stream"]; + delete ctx.MediaPath; + delete ctx.MediaType; + } + + applyInlineQuoteContext(ctx, msg); + return ctx; } +function findReferenceItem(msg: WeixinMessage): MessageItem | undefined { + return msg.item_list?.find((item) => item.ref_msg); +} + +function inlineQuoteBody(item: MessageItem): string | undefined { + const ref = item.ref_msg; + if (!ref) return undefined; + const parts: string[] = []; + if (ref.title?.trim()) parts.push(ref.title.trim()); + if (ref.message_item) { + const body = bodyFromItemList([ref.message_item]); + if (body) parts.push(body); + } + return parts.length ? parts.join(" | ") : undefined; +} + +function applyInlineQuoteContext(ctx: WeixinMsgContext, msg: WeixinMessage): void { + const item = findReferenceItem(msg); + if (!item?.ref_msg) return; + const replyToId = item.ref_msg.svr_id?.trim() || item.ref_msg.message_item?.msg_id?.trim(); + const body = inlineQuoteBody(item); + ctx.ReplyToIsQuote = true; + if (replyToId) ctx.ReplyToId = replyToId; + if (body) ctx.ReplyToBody = body; +} + +function expiredMediaLabel(mime?: string, name?: string): string { + const kind = mime?.startsWith("image/") + ? "图片" + : mime?.startsWith("video/") + ? "视频" + : mime?.startsWith("audio/") + ? "语音" + : "附件"; + return name ? `[引用的${kind}已过期: ${name}]` : `[引用的${kind}已过期]`; +} + +/** Resolve an ID-only quote after sender authorization has succeeded. */ +export function resolveStoredQuoteContext( + ctx: WeixinMsgContext, + msg: WeixinMessage, + accountId: string, + store: Pick | null = getQuoteStore(), +): void { + const item = findReferenceItem(msg); + const ref = item?.ref_msg; + const referenceId = ref?.svr_id?.trim() || ref?.message_item?.msg_id?.trim(); + if (!item || !ref || !referenceId) return; + + ctx.ReplyToId = referenceId; + ctx.ReplyToIsQuote = true; + if (ctx.ReplyToBody && (ref.title?.trim() || ref.message_item)) return; + const record = store?.find(accountId, ctx.From, referenceId); + if (!record) { + if (!ctx.ReplyToBody) ctx.ReplyToBody = "[引用消息内容未缓存]"; + return; + } + + ctx.ReplyToBody = record.body || expiredMediaLabel(record.mediaMime, record.mediaName); + if (ref.partial_text && record.body) { + const partial = resolvePartialQuote(record.body, ref.partial_text); + if (!partial.fallback && partial.resolved) ctx.ReplyToQuoteText = partial.resolved; + } + + if (!record.mediaPath) { + if (record.mediaMime || record.mediaName) { + ctx.ReplyToBody = expiredMediaLabel(record.mediaMime, record.mediaName); + } + return; + } + if (!fs.existsSync(record.mediaPath)) { + ctx.ReplyToBody = expiredMediaLabel(record.mediaMime, record.mediaName); + return; + } + const currentPaths = ctx.MediaPaths ?? (ctx.MediaPath ? [ctx.MediaPath] : []); + const currentTypes = + ctx.MediaTypes ?? (ctx.MediaPath ? [ctx.MediaType ?? "application/octet-stream"] : []); + ctx.MediaPaths = [...currentPaths, record.mediaPath]; + ctx.MediaTypes = [...currentTypes, record.mediaMime ?? "application/octet-stream"]; + ctx.media = ctx.MediaPaths.map((mediaPath, index) => ({ + path: mediaPath, + contentType: ctx.MediaTypes?.[index] ?? "application/octet-stream", + ...(index === ctx.MediaPaths!.length - 1 && record.mediaName + ? { fileName: record.mediaName } + : {}), + ...(index === ctx.MediaPaths!.length - 1 ? { messageId: referenceId } : {}), + })); + const quotedAttachment = { + message_id: referenceId, + original_filename: record.mediaName ?? path.basename(record.mediaPath), + managed_source_path: record.mediaPath, + workspace_directory: "media/inbound/", + }; + ctx.ChannelPromptContext = [ + ...(ctx.ChannelPromptContext ?? []), + [ + "Quoted attachment tool access:", + JSON.stringify(quotedAttachment), + "The attachment is staged into the agent workspace under media/inbound/. " + + "If automatic extraction fails and the user asks about its contents, use the available " + + "file/PDF tools to locate it by original_filename and read it.", + ].join("\n"), + ]; +} + /** Extract the context_token from an inbound WeixinMsgContext. */ export function getContextTokenFromMsgContext(ctx: WeixinMsgContext): string | undefined { return ctx.context_token; diff --git a/src/messaging/partial-quote.test.ts b/src/messaging/partial-quote.test.ts new file mode 100644 index 0000000..2fbcd9f --- /dev/null +++ b/src/messaging/partial-quote.test.ts @@ -0,0 +1,58 @@ +import crypto from "node:crypto"; + +import { describe, expect, it } from "vitest"; + +import { resolvePartialQuote } from "./partial-quote.js"; + +function md5(value: string): string { + return crypto.createHash("md5").update(value, "utf8").digest("hex"); +} + +describe("resolvePartialQuote", () => { + it("resolves the protocol example using global occurrence indexes", () => { + expect( + resolvePartialQuote("abcedfabcgh", { + start: "a", + end: "c", + startindex: 1, + endindex: 1, + quotemd5: md5("abc"), + }), + ).toEqual({ resolved: "abc", fallback: false }); + }); + + it("uses the hash to support end indexes relative to the selected start", () => { + const full = "x-end start first-end second-end"; + const selected = "start first-end second-end"; + expect( + resolvePartialQuote(full, { + start: "start", + end: "end", + startindex: 0, + endindex: 1, + quotemd5: md5(selected), + }), + ).toEqual({ resolved: selected, fallback: false }); + }); + + it("falls back when indexes are invalid or the hash does not match", () => { + expect( + resolvePartialQuote("hello", { + start: "h", + end: "o", + startindex: -1, + endindex: 0, + quotemd5: "", + }), + ).toEqual({ resolved: null, fallback: true }); + expect( + resolvePartialQuote("hello", { + start: "h", + end: "o", + startindex: 0, + endindex: 0, + quotemd5: "not-the-md5", + }), + ).toEqual({ resolved: null, fallback: true }); + }); +}); diff --git a/src/messaging/partial-quote.ts b/src/messaging/partial-quote.ts new file mode 100644 index 0000000..f00a546 --- /dev/null +++ b/src/messaging/partial-quote.ts @@ -0,0 +1,62 @@ +import crypto from "node:crypto"; + +import type { PartialText } from "../api/types.js"; + +export type PartialQuoteResult = { + resolved: string | null; + fallback: boolean; +}; + +function nthIndexOf(text: string, value: string, occurrence: number, fromIndex = 0): number { + if (!value || !Number.isInteger(occurrence) || occurrence < 0) return -1; + let position = fromIndex; + for (let current = 0; current <= occurrence; current++) { + position = text.indexOf(value, position); + if (position < 0) return -1; + if (current < occurrence) position += value.length; + } + return position; +} + +function hashQuote(text: string): string { + return crypto.createHash("md5").update(text, "utf8").digest("hex"); +} + +function candidate( + fullText: string, + partial: PartialText, + endSearchMode: "global" | "relative", +): string | null { + const start = nthIndexOf(fullText, partial.start, partial.startindex); + if (start < 0) return null; + const end = + endSearchMode === "global" + ? nthIndexOf(fullText, partial.end, partial.endindex) + : nthIndexOf(fullText, partial.end, partial.endindex, start + partial.start.length); + if (end < start) return null; + return fullText.slice(start, end + partial.end.length); +} + +/** + * Resolve both observed interpretations of endindex. When quotemd5 is present + * it disambiguates the protocol variants; without a hash, global indexes match + * the examples supplied with the newer Weixin payload definition. + */ +export function resolvePartialQuote(fullText: string, partial: PartialText): PartialQuoteResult { + if (!fullText || !partial.start || !partial.end) { + return { resolved: null, fallback: true }; + } + const candidates = [ + candidate(fullText, partial, "global"), + candidate(fullText, partial, "relative"), + ].filter((value, index, all): value is string => Boolean(value) && all.indexOf(value) === index); + + if (!partial.quotemd5) { + return candidates[0] + ? { resolved: candidates[0], fallback: false } + : { resolved: null, fallback: true }; + } + const expected = partial.quotemd5.toLowerCase(); + const resolved = candidates.find((value) => hashQuote(value) === expected) ?? null; + return { resolved, fallback: resolved === null }; +} diff --git a/src/messaging/process-message.ts b/src/messaging/process-message.ts index 633a6e6..b4c4322 100644 --- a/src/messaging/process-message.ts +++ b/src/messaging/process-message.ts @@ -27,13 +27,16 @@ import { setContextToken, weixinMessageToMsgContext, getContextTokenFromMsgContext, + getWeixinMessageId, isMediaItem, + resolveStoredQuoteContext, } from "./inbound.js"; import type { WeixinInboundMediaOpts } from "./inbound.js"; import { sendWeixinMediaFile } from "./send-media.js"; import { StreamingMarkdownFilter } from "./markdown-filter.js"; import { sendMessageWeixin } from "./send.js"; import { WeixinReplyProgressSender } from "./reply-progress-sender.js"; +import { getActiveQuoteMediaSubdir, getQuoteStore } from "./quote-store.js"; import { handleSlashCommand } from "./slash-commands.js"; const MEDIA_OUTBOUND_TEMP_DIR = path.join( @@ -156,11 +159,13 @@ export async function processOneMessage( const downloaded = await downloadMediaFromItem(mediaItem, { cdnBaseUrl: deps.cdnBaseUrl, saveMedia: deps.channelRuntime.media.saveMediaBuffer, + mediaSubdir: getActiveQuoteMediaSubdir(deps.accountId), log: deps.log, errLog: deps.errLog, label, }); Object.assign(mediaOpts, downloaded); + if (refMediaItem) mediaOpts.referencedMedia = true; } const mediaDownloadMs = Date.now() - mediaDownloadStart; @@ -223,6 +228,30 @@ export async function processOneMessage( ); } + resolveStoredQuoteContext(ctx, full, deps.accountId); + const inboundMessageId = getWeixinMessageId(full); + if (inboundMessageId) { + try { + await getQuoteStore()?.put({ + accountId: deps.accountId, + conversationId: senderId, + messageId: inboundMessageId, + direction: "inbound", + body: ctx.Body, + ...(ctx.MediaPath ? { sourceMediaPath: ctx.MediaPath } : {}), + ...(ctx.MediaType ? { mediaMime: ctx.MediaType } : {}), + ...(mainMediaItem?.file_item?.file_name + ? { mediaName: mainMediaItem.file_item.file_name } + : {}), + createdAt: full.create_time_ms ?? Date.now(), + }); + } catch (err) { + logger.warn( + `quote cache: failed to save inbound message id=${inboundMessageId}: ${String(err)}`, + ); + } + } + const route = deps.channelRuntime.routing.resolveAgentRoute({ cfg: deps.config, channel: "openclaw-weixin", @@ -290,6 +319,7 @@ export async function processOneMessage( baseUrl: deps.baseUrl, token: deps.token, contextToken, + accountId: deps.accountId, }, }) : undefined; @@ -397,6 +427,7 @@ export async function processOneMessage( token: deps.token, contextToken, runId, + accountId: deps.accountId, }, }); emitWeixinMessageSent({ @@ -413,7 +444,13 @@ export async function processOneMessage( filePath, to: ctx.To, text, - opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId }, + opts: { + baseUrl: deps.baseUrl, + token: deps.token, + contextToken, + runId, + accountId: deps.accountId, + }, cdnBaseUrl: deps.cdnBaseUrl, }); emitWeixinMessageSent({ @@ -434,6 +471,7 @@ export async function processOneMessage( token: deps.token, contextToken, runId, + accountId: deps.accountId, }, }); emitWeixinMessageSent({ @@ -482,6 +520,7 @@ export async function processOneMessage( baseUrl: deps.baseUrl, token: deps.token, runId, + accountId: deps.accountId, errLog: deps.errLog, }); }, @@ -553,7 +592,13 @@ export async function processOneMessage( await sendMessageWeixin({ to: ctx.To, text: timingText, - opts: { baseUrl: deps.baseUrl, token: deps.token, contextToken, runId }, + opts: { + baseUrl: deps.baseUrl, + token: deps.token, + contextToken, + runId, + accountId: deps.accountId, + }, }); logger.info(`debug-timing: sent OK`); } catch (debugErr) { diff --git a/src/messaging/quote-store.test.ts b/src/messaging/quote-store.test.ts new file mode 100644 index 0000000..432aef9 --- /dev/null +++ b/src/messaging/quote-store.test.ts @@ -0,0 +1,616 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; + +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +import type { QuoteCachePolicy } from "./quote-store.js"; +import { + QuoteStore, + closeQuoteStore, + deactivateQuoteStoreAccount, + deleteQuoteCacheForAccount, + getActiveQuoteMediaSubdir, + getQuoteStore, + initializeQuoteStore, + resolveQuoteMediaSubdir, + resolveQuoteCachePolicy, +} from "./quote-store.js"; + +vi.mock("../util/logger.js", () => ({ + logger: { + info: vi.fn(), + debug: vi.fn(), + warn: vi.fn(), + error: vi.fn(), + }, +})); + +let rootDir: string; +let mediaRoot: string; +let stores: QuoteStore[]; + +function policy(overrides: Partial = {}): QuoteCachePolicy { + return { + enabled: true, + retentionMs: 30 * 24 * 60 * 60 * 1000, + maxMessagesPerAccount: 10_000, + mediaRetentionMs: 7 * 24 * 60 * 60 * 1000, + maxMediaBytesPerAccount: 256 * 1024 * 1024, + maxSingleMediaBytes: 25 * 1024 * 1024, + ...overrides, + }; +} + +async function open(overrides: Partial = {}): Promise { + const store = await QuoteStore.open({ rootDir, mediaRoot, policy: policy(overrides) }); + expect(store).not.toBeNull(); + stores.push(store!); + return store!; +} + +function managedMediaPath(accountId: string, fileName: string): string { + const accountDir = path.join(mediaRoot, path.basename(resolveQuoteMediaSubdir(accountId))); + fs.mkdirSync(accountDir, { recursive: true }); + return path.join(accountDir, fileName); +} + +beforeEach(() => { + rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "weixin-quote-store-")); + mediaRoot = path.join(rootDir, "managed-media"); + stores = []; +}); + +afterEach(() => { + closeQuoteStore(); + delete process.env.OPENCLAW_STATE_DIR; + for (const store of stores) store.close(); + fs.rmSync(rootDir, { recursive: true, force: true }); +}); + +describe("QuoteStore", () => { + it("persists lossless IDs and scopes records by account and conversation", async () => { + const store = await open(); + const createdAt = Date.now(); + await store.put({ + accountId: "account-a", + conversationId: "user-a", + messageId: "18446744073709551615", + direction: "inbound", + body: "hello", + createdAt, + }); + + expect(store.find("account-a", "user-a", "18446744073709551615")?.body).toBe("hello"); + expect(store.find("account-b", "user-a", "18446744073709551615")).toBeNull(); + expect(store.find("account-a", "user-b", "18446744073709551615")).toBeNull(); + + store.close(); + const reopened = await open(); + expect(reopened.find("account-a", "user-a", "18446744073709551615")).toMatchObject({ + messageId: "18446744073709551615", + body: "hello", + createdAt, + }); + }); + + it("evicts expired and over-count messages during GC", async () => { + const now = Date.now(); + const store = await open({ retentionMs: 100, maxMessagesPerAccount: 2 }); + for (let index = 0; index < 3; index++) { + await store.put({ + accountId: "account", + conversationId: "user", + messageId: String(index), + direction: "inbound", + body: `message-${index}`, + createdAt: now + index, + }); + } + store.runGc(now + 3); + expect(store.find("account", "user", "0")).toBeNull(); + expect(store.find("account", "user", "1")?.body).toBe("message-1"); + expect(store.find("account", "user", "2")?.body).toBe("message-2"); + + store.runGc(now + 1000); + expect(store.find("account", "user", "1")).toBeNull(); + expect(store.find("account", "user", "2")).toBeNull(); + }); + + it("registers one managed media copy and deletes it with the account", async () => { + const store = await open(); + const source = managedMediaPath("account", "source.png"); + fs.writeFileSync(source, "same-content"); + for (const messageId of ["1", "2"]) { + await store.put({ + accountId: "account", + conversationId: "user", + messageId, + direction: "inbound", + body: "[图片]", + sourceMediaPath: source, + mediaMime: "image/png", + createdAt: Date.now(), + }); + } + const first = store.find("account", "user", "1"); + const second = store.find("account", "user", "2"); + expect(first?.mediaPath).toBe(second?.mediaPath); + expect(first?.mediaPath).toBe(source); + expect(fs.readFileSync(first!.mediaPath!, "utf8")).toBe("same-content"); + + const managedPath = first!.mediaPath!; + store.deleteAccount("account"); + expect(store.find("account", "user", "1")).toBeNull(); + expect(fs.existsSync(managedPath)).toBe(false); + }); + + it("does not let sanitized account names share a media directory", async () => { + const store = await open(); + for (const accountId of ["a/b", "a_b"]) { + const source = managedMediaPath(accountId, "source.png"); + fs.writeFileSync(source, "same-content"); + await store.put({ + accountId, + conversationId: "user", + messageId: "1", + direction: "inbound", + body: "[图片]", + sourceMediaPath: source, + createdAt: Date.now(), + }); + } + const firstPath = store.find("a/b", "user", "1")!.mediaPath!; + const secondPath = store.find("a_b", "user", "1")!.mediaPath!; + expect(path.dirname(firstPath)).not.toBe(path.dirname(secondPath)); + store.deleteAccount("a/b"); + expect(fs.existsSync(firstPath)).toBe(false); + expect(fs.existsSync(secondPath)).toBe(true); + }); + + it("keeps message metadata but skips oversized media", async () => { + const store = await open({ maxSingleMediaBytes: 4 }); + const source = managedMediaPath("account", "large.bin"); + fs.writeFileSync(source, "12345"); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "large", + direction: "inbound", + body: "[文件]", + sourceMediaPath: source, + mediaMime: "application/octet-stream", + mediaName: "large.bin", + createdAt: Date.now(), + }); + expect(store.find("account", "user", "large")).toMatchObject({ + body: "[文件]", + mediaMime: "application/octet-stream", + mediaName: "large.bin", + }); + expect(store.find("account", "user", "large")?.mediaPath).toBeUndefined(); + }); + + it("enforces the per-account media byte budget oldest-first", async () => { + const store = await open({ maxMediaBytesPerAccount: 4 }); + const firstSource = managedMediaPath("account", "first.bin"); + const secondSource = managedMediaPath("account", "second.bin"); + fs.writeFileSync(firstSource, "1111"); + fs.writeFileSync(secondSource, "2222"); + const now = Date.now(); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "1", + direction: "inbound", + body: "[文件]", + sourceMediaPath: firstSource, + createdAt: now, + }); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "2", + direction: "inbound", + body: "[文件]", + sourceMediaPath: secondSource, + createdAt: now + 1, + }); + expect(store.find("account", "user", "1")?.mediaPath).toBeUndefined(); + expect(store.find("account", "user", "2")?.mediaPath).toBeDefined(); + }); + + it("expires managed media without discarding the message body", async () => { + const store = await open({ mediaRetentionMs: 10 }); + const source = managedMediaPath("account", "old.mp3"); + fs.writeFileSync(source, "voice"); + const now = Date.now(); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "old-media", + direction: "inbound", + body: "[语音]", + sourceMediaPath: source, + mediaMime: "audio/mpeg", + createdAt: now, + }); + const managedPath = store.find("account", "user", "old-media")!.mediaPath!; + store.runGc(now + 20); + expect(store.find("account", "user", "old-media")).toMatchObject({ + body: "[语音]", + mediaMime: "audio/mpeg", + }); + expect(store.find("account", "user", "old-media")?.mediaPath).toBeUndefined(); + expect(fs.existsSync(managedPath)).toBe(false); + }); + + it("removes an expired message but preserves media shared by a newer record", async () => { + const store = await open({ retentionMs: 100 }); + const source = managedMediaPath("account", "shared.png"); + fs.writeFileSync(source, "shared"); + const now = Date.now(); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "old", + direction: "inbound", + body: "old", + sourceMediaPath: source, + createdAt: now - 1000, + }); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "new", + direction: "inbound", + body: "new", + sourceMediaPath: source, + createdAt: now, + }); + const managedPath = store.find("account", "user", "new")!.mediaPath!; + expect(store.find("account", "user", "old")).toBeNull(); + expect(fs.existsSync(managedPath)).toBe(true); + }); + + it("prunes orphan files and tolerates a missing media source", async () => { + const store = await open(); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "missing", + direction: "inbound", + body: "[文件]", + sourceMediaPath: path.join(rootDir, "does-not-exist.bin"), + createdAt: Date.now(), + }); + expect(store.find("account", "user", "missing")?.mediaPath).toBeUndefined(); + + const orphanDir = path.join(mediaRoot, "nested"); + fs.mkdirSync(orphanDir, { recursive: true }); + const orphan = path.join(orphanDir, "orphan.bin"); + fs.writeFileSync(orphan, "orphan"); + store.runGc(); + expect(fs.existsSync(orphan)).toBe(false); + }); + + it("applies policy updates asynchronously", async () => { + const store = await open(); + const now = Date.now(); + for (const messageId of ["1", "2"]) { + await store.put({ + accountId: "account", + conversationId: "user", + messageId, + direction: "inbound", + body: messageId, + createdAt: now, + }); + } + store.updatePolicy(policy({ maxMessagesPerAccount: 1 })); + await new Promise((resolve) => queueMicrotask(resolve)); + const remaining = ["1", "2"].filter((id) => store.find("account", "user", id)); + expect(remaining).toHaveLength(1); + }); + + it("does not open when explicitly disabled", async () => { + await expect( + QuoteStore.open({ rootDir, policy: policy({ enabled: false }) }), + ).resolves.toBeNull(); + }); + + it("returns null when the database directory cannot be created", async () => { + const fileInsteadOfDirectory = path.join(rootDir, "plain-file"); + fs.writeFileSync(fileInsteadOfDirectory, "not a directory"); + await expect( + QuoteStore.open({ + rootDir: path.join(fileInsteadOfDirectory, "child"), + policy: policy(), + }), + ).resolves.toBeNull(); + }); + + it("ignores invalid writes, isolates unsafe account names, and substitutes invalid timestamps", async () => { + const store = await open(); + const source = managedMediaPath(" ", "media"); + fs.writeFileSync(source, "content"); + await store.put({ + accountId: " ", + conversationId: "user", + messageId: "media", + direction: "inbound", + body: "[文件]", + sourceMediaPath: source, + createdAt: Number.NaN, + }); + const record = store.find(" ", "user", "media"); + expect(record?.createdAt).toBeGreaterThan(0); + expect(record?.mediaPath).toContain(`${path.sep}default-`); + expect(path.extname(record!.mediaPath!)).toBe(""); + + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "", + direction: "inbound", + body: "ignored", + createdAt: Date.now(), + }); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "empty", + direction: "inbound", + body: "", + createdAt: Date.now(), + }); + expect(store.find("account", "user", "")).toBeNull(); + expect(store.find("account", "user", "empty")).toBeNull(); + + store.close(); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "closed", + direction: "inbound", + body: "ignored", + createdAt: Date.now(), + }); + expect(store.find("account", "user", "closed")).toBeNull(); + store.deleteAccount("account"); + store.runGc(); + }); + + it("refuses to claim media outside its account-owned directory", async () => { + const source = path.join(rootDir, "outside.bin"); + fs.writeFileSync(source, "content"); + const store = await open(); + await store.put({ + accountId: "account", + conversationId: "user", + messageId: "outside", + direction: "inbound", + body: "[文件]", + sourceMediaPath: source, + createdAt: Date.now(), + }); + expect(store.find("account", "user", "outside")?.mediaPath).toBeUndefined(); + expect(fs.existsSync(source)).toBe(true); + }); + + it("moves legacy media into the OpenClaw-managed cache and rewrites its database path", async () => { + const legacyRoot = path.join(rootDir, "ref-media"); + const legacyStore = await QuoteStore.open({ + rootDir, + mediaRoot: legacyRoot, + policy: policy(), + }); + expect(legacyStore).not.toBeNull(); + stores.push(legacyStore!); + const legacyPath = path.join( + legacyRoot, + path.basename(resolveQuoteMediaSubdir("account")), + "legacy.pdf", + ); + fs.mkdirSync(path.dirname(legacyPath), { recursive: true }); + fs.writeFileSync(legacyPath, "pdf"); + await legacyStore!.put({ + accountId: "account", + conversationId: "user", + messageId: "legacy", + direction: "inbound", + body: "[文件]", + sourceMediaPath: legacyPath, + mediaName: "report.pdf", + createdAt: Date.now(), + }); + await legacyStore!.put({ + accountId: "account", + conversationId: "user", + messageId: "legacy-shared", + direction: "inbound", + body: "[文件]", + sourceMediaPath: legacyPath, + mediaName: "report.pdf", + createdAt: Date.now(), + }); + + const existingLegacyPath = path.join(path.dirname(legacyPath), "existing.pdf"); + fs.writeFileSync(existingLegacyPath, "existing"); + await legacyStore!.put({ + accountId: "account", + conversationId: "user", + messageId: "existing", + direction: "inbound", + body: "[文件]", + sourceMediaPath: existingLegacyPath, + createdAt: Date.now(), + }); + const existingManagedPath = managedMediaPath("account", "existing.pdf"); + fs.writeFileSync(existingManagedPath, "existing"); + + const missingLegacyPath = path.join(path.dirname(legacyPath), "missing.pdf"); + fs.writeFileSync(missingLegacyPath, "missing"); + await legacyStore!.put({ + accountId: "account", + conversationId: "user", + messageId: "missing-legacy", + direction: "inbound", + body: "[文件]", + sourceMediaPath: missingLegacyPath, + createdAt: Date.now(), + }); + fs.unlinkSync(missingLegacyPath); + legacyStore!.close(); + + const migratedStore = await open(); + const migrated = migratedStore.find("account", "user", "legacy"); + expect(migrated?.mediaPath).toBe(managedMediaPath("account", "legacy.pdf")); + expect(migrated?.mediaName).toBe("report.pdf"); + expect(fs.existsSync(migrated!.mediaPath!)).toBe(true); + expect(fs.existsSync(legacyPath)).toBe(false); + expect(migratedStore.find("account", "user", "legacy-shared")?.mediaPath).toBe( + migrated?.mediaPath, + ); + expect(migratedStore.find("account", "user", "existing")?.mediaPath).toBe(existingManagedPath); + expect(fs.existsSync(existingLegacyPath)).toBe(false); + }); +}); + +describe("global quote store lifecycle", () => { + it("shares one store across active accounts and closes after the last account stops", async () => { + process.env.OPENCLAW_STATE_DIR = rootDir; + expect(getActiveQuoteMediaSubdir("account-a")).toBeUndefined(); + const first = await initializeQuoteStore({}, "account-a"); + const second = await initializeQuoteStore({}, "account-b"); + expect(first).toBe(second); + expect(getQuoteStore()).toBe(first); + expect(getActiveQuoteMediaSubdir("account-a")).toBe(resolveQuoteMediaSubdir("account-a")); + + deactivateQuoteStoreAccount("account-a"); + expect(getQuoteStore()).toBe(first); + deactivateQuoteStoreAccount("account-b"); + expect(getQuoteStore()).toBeNull(); + }); + + it("honors explicit disablement", async () => { + process.env.OPENCLAW_STATE_DIR = rootDir; + await expect( + initializeQuoteStore( + { + channels: { "openclaw-weixin": { quoteCache: { enabled: false } } }, + }, + "account", + ), + ).resolves.toBeNull(); + expect(getQuoteStore()).toBeNull(); + }); + + it("closes an already-active store when the feature is disabled", async () => { + process.env.OPENCLAW_STATE_DIR = rootDir; + expect(await initializeQuoteStore({}, "account")).not.toBeNull(); + await expect( + initializeQuoteStore( + { + channels: { "openclaw-weixin": { quoteCache: { enabled: false } } }, + }, + "account", + ), + ).resolves.toBeNull(); + expect(getQuoteStore()).toBeNull(); + }); + + it("deletes an account through the active singleton", async () => { + process.env.OPENCLAW_STATE_DIR = rootDir; + const store = await initializeQuoteStore({}, "account"); + await store!.put({ + accountId: "account", + conversationId: "user", + messageId: "1", + direction: "inbound", + body: "hello", + createdAt: Date.now(), + }); + deleteQuoteCacheForAccount("account"); + expect(store!.find("account", "user", "1")).toBeNull(); + }); + + it("deletes an account from a closed on-disk database", async () => { + process.env.OPENCLAW_STATE_DIR = rootDir; + const managedRoot = path.join(rootDir, "openclaw-weixin"); + const store = await QuoteStore.open({ rootDir: managedRoot, policy: policy() }); + expect(store).not.toBeNull(); + await store!.put({ + accountId: "account", + conversationId: "user", + messageId: "1", + direction: "inbound", + body: "hello", + createdAt: Date.now(), + }); + store!.close(); + + deleteQuoteCacheForAccount("account"); + const reopened = await QuoteStore.open({ rootDir: managedRoot, policy: policy() }); + expect(reopened?.find("account", "user", "1")).toBeNull(); + reopened?.close(); + }); +}); + +describe("resolveQuoteCachePolicy", () => { + it("uses safe defaults and honors explicit disablement", () => { + expect(resolveQuoteCachePolicy({})).toMatchObject({ + enabled: true, + maxMessagesPerAccount: 10_000, + maxMediaBytesPerAccount: 256 * 1024 * 1024, + }); + expect( + resolveQuoteCachePolicy({ + channels: { "openclaw-weixin": { quoteCache: { enabled: false } } }, + }), + ).toMatchObject({ enabled: false }); + }); + + it("accepts positive limits and replaces invalid values with defaults", () => { + expect( + resolveQuoteCachePolicy({ + channels: { + "openclaw-weixin": { + quoteCache: { + retentionDays: 2, + maxMessagesPerAccount: 3.9, + mediaRetentionDays: 4, + maxMediaBytesPerAccount: 5, + maxSingleMediaBytes: 6, + }, + }, + }, + }), + ).toMatchObject({ + retentionMs: 2 * 24 * 60 * 60 * 1000, + maxMessagesPerAccount: 3, + mediaRetentionMs: 4 * 24 * 60 * 60 * 1000, + maxMediaBytesPerAccount: 5, + maxSingleMediaBytes: 6, + }); + expect( + resolveQuoteCachePolicy({ + channels: { + "openclaw-weixin": { + quoteCache: { + retentionDays: Number.NaN, + maxMessagesPerAccount: 0, + mediaRetentionDays: -1, + maxMediaBytesPerAccount: Number.POSITIVE_INFINITY, + maxSingleMediaBytes: 0, + }, + }, + }, + }), + ).toMatchObject({ + maxMessagesPerAccount: 10_000, + maxMediaBytesPerAccount: 256 * 1024 * 1024, + maxSingleMediaBytes: 25 * 1024 * 1024, + }); + }); +}); diff --git a/src/messaging/quote-store.ts b/src/messaging/quote-store.ts new file mode 100644 index 0000000..d0e3f74 --- /dev/null +++ b/src/messaging/quote-store.ts @@ -0,0 +1,656 @@ +import crypto from "node:crypto"; +import fs from "node:fs"; +import { createRequire } from "node:module"; +import path from "node:path"; + +import type { OpenClawConfig } from "openclaw/plugin-sdk/core"; + +import { resolveStateDir } from "../storage/state-dir.js"; +import { logger } from "../util/logger.js"; + +const DEFAULT_RETENTION_DAYS = 30; +const DEFAULT_MAX_MESSAGES_PER_ACCOUNT = 10_000; +const DEFAULT_MEDIA_RETENTION_DAYS = 7; +const DEFAULT_MAX_MEDIA_BYTES_PER_ACCOUNT = 256 * 1024 * 1024; +const DEFAULT_MAX_SINGLE_MEDIA_BYTES = 25 * 1024 * 1024; +const GC_WRITE_INTERVAL = 100; +const GC_TIMER_MS = 60 * 60 * 1000; +const QUOTE_MEDIA_SUBDIR = "inbound/openclaw-weixin-quotes"; + +type SqliteStatement = { + run: (...params: unknown[]) => unknown; + get: (...params: unknown[]) => unknown; + all: (...params: unknown[]) => unknown[]; +}; + +type SqliteDatabase = { + exec: (sql: string) => void; + prepare: (sql: string) => SqliteStatement; + close: () => void; +}; + +type DatabaseSyncConstructor = new (filePath: string) => SqliteDatabase; + +export type QuoteCachePolicy = { + enabled: boolean; + retentionMs: number; + maxMessagesPerAccount: number; + mediaRetentionMs: number; + maxMediaBytesPerAccount: number; + maxSingleMediaBytes: number; +}; + +export type QuoteMessageRecord = { + accountId: string; + conversationId: string; + messageId: string; + direction: "inbound" | "outbound"; + body: string; + mediaPath?: string; + mediaMime?: string; + mediaName?: string; + mediaSize?: number; + createdAt: number; +}; + +export type QuoteMessageInput = Omit & { + sourceMediaPath?: string; +}; + +type QuoteCacheConfig = { + enabled?: boolean; + retentionDays?: number; + maxMessagesPerAccount?: number; + mediaRetentionDays?: number; + maxMediaBytesPerAccount?: number; + maxSingleMediaBytes?: number; +}; + +type WeixinChannelConfig = { + quoteCache?: QuoteCacheConfig; +}; + +type StoredRow = { + account_id: string; + conversation_id: string; + message_id: string; + direction: "inbound" | "outbound"; + body: string; + media_path: string | null; + media_mime: string | null; + media_name: string | null; + media_size: number | null; + created_at: number; +}; + +type MediaRow = { + media_path: string; + media_size: number; + newest_at: number; +}; + +function positiveNumber(value: unknown, fallback: number): number { + return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback; +} + +function positiveInteger(value: unknown, fallback: number): number { + return Math.max(1, Math.floor(positiveNumber(value, fallback))); +} + +export function resolveQuoteCachePolicy(cfg: OpenClawConfig): QuoteCachePolicy { + const section = cfg.channels?.["openclaw-weixin"] as WeixinChannelConfig | undefined; + const quote = section?.quoteCache; + return { + enabled: quote?.enabled !== false, + retentionMs: positiveNumber(quote?.retentionDays, DEFAULT_RETENTION_DAYS) * 24 * 60 * 60 * 1000, + maxMessagesPerAccount: positiveInteger( + quote?.maxMessagesPerAccount, + DEFAULT_MAX_MESSAGES_PER_ACCOUNT, + ), + mediaRetentionMs: + positiveNumber(quote?.mediaRetentionDays, DEFAULT_MEDIA_RETENTION_DAYS) * 24 * 60 * 60 * 1000, + maxMediaBytesPerAccount: positiveInteger( + quote?.maxMediaBytesPerAccount, + DEFAULT_MAX_MEDIA_BYTES_PER_ACCOUNT, + ), + maxSingleMediaBytes: positiveInteger( + quote?.maxSingleMediaBytes, + DEFAULT_MAX_SINGLE_MEDIA_BYTES, + ), + }; +} + +function safePathSegment(raw: string): string { + const safe = raw + .trim() + .toLowerCase() + .replace(/[^a-z0-9._-]+/g, "_") + .replace(/\.\.+/g, "_"); + return safe && safe !== "." && safe !== ".." ? safe : "default"; +} + +function accountMediaDirName(accountId: string): string { + const readable = safePathSegment(accountId).slice(0, 48); + const digest = crypto.createHash("sha256").update(accountId, "utf8").digest("hex").slice(0, 16); + return `${readable}-${digest}`; +} + +/** OpenClaw media-store subdirectory owned and garbage-collected by this plugin. */ +export function resolveQuoteMediaSubdir(accountId: string): string { + return path.posix.join(QUOTE_MEDIA_SUBDIR, accountMediaDirName(accountId)); +} + +function resolveQuoteMediaRoot(): string { + return path.join(resolveStateDir(), "media", ...QUOTE_MEDIA_SUBDIR.split("/")); +} + +function asStoredRow(value: unknown): StoredRow | null { + if (!value || typeof value !== "object") return null; + return value as StoredRow; +} + +export class QuoteStore { + private readonly db: SqliteDatabase; + private readonly rootDir: string; + private readonly mediaRoot: string; + private policy: QuoteCachePolicy; + private writesSinceGc = 0; + private gcRunning = false; + private gcRequested = false; + private gcScheduled = false; + private closed = false; + private readonly gcTimer: ReturnType; + + private constructor( + db: SqliteDatabase, + rootDir: string, + mediaRoot: string, + policy: QuoteCachePolicy, + ) { + this.db = db; + this.rootDir = rootDir; + this.mediaRoot = mediaRoot; + this.policy = policy; + this.initializeSchema(); + this.migrateLegacyMedia(); + this.gcTimer = setInterval(() => this.requestGc(), GC_TIMER_MS); + this.gcTimer.unref(); + this.runGc(); + } + + static async open(params: { + policy: QuoteCachePolicy; + rootDir?: string; + mediaRoot?: string; + }): Promise { + if (!params.policy.enabled) return null; + try { + const sqlite = (await import("node:sqlite")) as unknown as { + DatabaseSync: DatabaseSyncConstructor; + }; + const rootDir = params.rootDir ?? path.join(resolveStateDir(), "openclaw-weixin"); + const mediaRoot = params.mediaRoot ?? resolveQuoteMediaRoot(); + fs.mkdirSync(rootDir, { recursive: true, mode: 0o700 }); + fs.mkdirSync(mediaRoot, { recursive: true, mode: 0o700 }); + try { + fs.chmodSync(rootDir, 0o700); + } catch { + // best-effort on filesystems without POSIX permissions + } + const dbPath = path.join(rootDir, "ref-messages.sqlite"); + const db = new sqlite.DatabaseSync(dbPath); + try { + fs.chmodSync(dbPath, 0o600); + } catch { + // best-effort + } + return new QuoteStore(db, rootDir, mediaRoot, params.policy); + } catch (err) { + logger.warn( + `quote cache disabled: node:sqlite is unavailable or the database could not be opened: ${String(err)}`, + ); + return null; + } + } + + updatePolicy(policy: QuoteCachePolicy): void { + this.policy = policy; + this.requestGc(); + } + + private initializeSchema(): void { + this.db.exec(` + PRAGMA journal_mode = WAL; + PRAGMA synchronous = NORMAL; + PRAGMA busy_timeout = 5000; + CREATE TABLE IF NOT EXISTS quote_messages ( + account_id TEXT NOT NULL, + conversation_id TEXT NOT NULL, + message_id TEXT NOT NULL, + direction TEXT NOT NULL, + body TEXT NOT NULL DEFAULT '', + media_path TEXT, + media_mime TEXT, + media_name TEXT, + media_size INTEGER, + created_at INTEGER NOT NULL, + PRIMARY KEY (account_id, conversation_id, message_id) + ); + CREATE INDEX IF NOT EXISTS quote_messages_account_created + ON quote_messages (account_id, created_at); + CREATE INDEX IF NOT EXISTS quote_messages_media_path + ON quote_messages (media_path); + `); + } + + /** Move media written by pre-managed-root builds without duplicating file contents. */ + private migrateLegacyMedia(): void { + const legacyRoots = [ + path.join(this.rootDir, "ref-media"), + // A short-lived local build accidentally omitted the media/ segment. + path.join(path.dirname(this.rootDir), ...QUOTE_MEDIA_SUBDIR.split("/")), + ]; + for (const legacyRoot of new Set(legacyRoots)) { + this.migrateLegacyMediaRoot(legacyRoot); + } + } + + private migrateLegacyMediaRoot(legacyRoot: string): void { + if (path.resolve(legacyRoot) === path.resolve(this.mediaRoot) || !fs.existsSync(legacyRoot)) { + return; + } + const rows = this.db + .prepare(` + SELECT account_id, media_path + FROM quote_messages + WHERE media_path IS NOT NULL + `) + .all() as Array<{ account_id: string; media_path: string }>; + const canonicalLegacyRoot = fs.realpathSync(legacyRoot); + const migrated = new Map(); + for (const row of rows) { + if (migrated.has(row.media_path)) continue; + if (!fs.existsSync(row.media_path)) continue; + const canonicalLegacyPath = fs.realpathSync(row.media_path); + const relative = path.relative(canonicalLegacyRoot, canonicalLegacyPath); + if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) continue; + const destinationDir = path.join(this.mediaRoot, accountMediaDirName(row.account_id)); + const destination = path.join(destinationDir, path.basename(row.media_path)); + try { + fs.mkdirSync(destinationDir, { recursive: true, mode: 0o700 }); + if (!fs.existsSync(destination)) { + try { + fs.renameSync(row.media_path, destination); + } catch (err) { + if ((err as NodeJS.ErrnoException).code !== "EXDEV") throw err; + fs.copyFileSync(row.media_path, destination, fs.constants.COPYFILE_EXCL); + fs.unlinkSync(row.media_path); + } + } else { + fs.unlinkSync(row.media_path); + } + migrated.set(row.media_path, destination); + } catch (err) { + logger.warn(`quote cache: failed to migrate media path=${row.media_path}: ${String(err)}`); + } + } + for (const [legacyPath, managedPath] of migrated) { + this.db + .prepare("UPDATE quote_messages SET media_path = ? WHERE media_path = ?") + .run(managedPath, legacyPath); + } + } + + find(accountId: string, conversationId: string, messageId: string): QuoteMessageRecord | null { + if (this.closed || !messageId) return null; + const row = asStoredRow( + this.db + .prepare(` + SELECT account_id, conversation_id, message_id, direction, body, + media_path, media_mime, media_name, media_size, created_at + FROM quote_messages + WHERE account_id = ? AND conversation_id = ? AND message_id = ? + `) + .get(accountId, conversationId, messageId), + ); + if (!row) return null; + if (Date.now() - row.created_at > this.policy.retentionMs) { + this.deleteMessage(accountId, conversationId, messageId); + return null; + } + return { + accountId: row.account_id, + conversationId: row.conversation_id, + messageId: row.message_id, + direction: row.direction, + body: row.body, + ...(row.media_path ? { mediaPath: row.media_path } : {}), + ...(row.media_mime ? { mediaMime: row.media_mime } : {}), + ...(row.media_name ? { mediaName: row.media_name } : {}), + ...(typeof row.media_size === "number" ? { mediaSize: row.media_size } : {}), + createdAt: row.created_at, + }; + } + + async put(input: QuoteMessageInput): Promise { + if (this.closed || !input.messageId || (!input.body && !input.sourceMediaPath)) return; + const media = input.sourceMediaPath + ? await this.registerManagedMedia(input.accountId, input.sourceMediaPath, input.mediaMime) + : null; + this.db + .prepare(` + INSERT INTO quote_messages ( + account_id, conversation_id, message_id, direction, body, + media_path, media_mime, media_name, media_size, created_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON CONFLICT(account_id, conversation_id, message_id) DO UPDATE SET + direction = excluded.direction, + body = excluded.body, + media_path = COALESCE(excluded.media_path, quote_messages.media_path), + media_mime = COALESCE(excluded.media_mime, quote_messages.media_mime), + media_name = COALESCE(excluded.media_name, quote_messages.media_name), + media_size = COALESCE(excluded.media_size, quote_messages.media_size), + created_at = excluded.created_at + `) + .run( + input.accountId, + input.conversationId, + input.messageId, + input.direction, + input.body, + media?.path ?? null, + input.mediaMime ?? media?.mime ?? null, + input.mediaName ?? media?.name ?? null, + media?.size ?? null, + Number.isFinite(input.createdAt) && input.createdAt > 0 ? input.createdAt : Date.now(), + ); + + this.writesSinceGc += 1; + if (media) { + this.enforceMediaBudget(input.accountId); + } + if (this.writesSinceGc >= GC_WRITE_INTERVAL) { + this.writesSinceGc = 0; + this.requestGc(); + } + } + + deleteAccount(accountId: string): void { + if (this.closed) return; + this.db.prepare("DELETE FROM quote_messages WHERE account_id = ?").run(accountId); + const accountMediaDir = path.join(this.mediaRoot, accountMediaDirName(accountId)); + try { + fs.rmSync(accountMediaDir, { recursive: true, force: true }); + } catch (err) { + logger.warn(`quote cache: failed to remove media for account=${accountId}: ${String(err)}`); + } + } + + private deleteMessage(accountId: string, conversationId: string, messageId: string): void { + const existing = this.findMediaPath(accountId, conversationId, messageId); + this.db + .prepare( + "DELETE FROM quote_messages WHERE account_id = ? AND conversation_id = ? AND message_id = ?", + ) + .run(accountId, conversationId, messageId); + if (existing) this.removeMediaIfOrphaned(existing); + } + + private findMediaPath( + accountId: string, + conversationId: string, + messageId: string, + ): string | null { + const row = this.db + .prepare( + "SELECT media_path FROM quote_messages WHERE account_id = ? AND conversation_id = ? AND message_id = ?", + ) + .get(accountId, conversationId, messageId) as { media_path?: unknown } | undefined; + return typeof row?.media_path === "string" ? row.media_path : null; + } + + private async registerManagedMedia( + accountId: string, + sourcePath: string, + mime?: string, + ): Promise<{ path: string; mime?: string; name: string; size: number } | null> { + try { + const accountDir = path.join(this.mediaRoot, accountMediaDirName(accountId)); + const canonicalRoot = await fs.promises + .realpath(accountDir) + .catch(() => path.resolve(accountDir)); + const canonicalSource = await fs.promises.realpath(sourcePath); + const relative = path.relative(canonicalRoot, canonicalSource); + if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) { + logger.warn(`quote cache: refusing unmanaged media path=${sourcePath}`); + return null; + } + const stat = await fs.promises.stat(canonicalSource); + if (!stat.isFile() || stat.size > this.policy.maxSingleMediaBytes) return null; + return { + path: path.resolve(sourcePath), + ...(mime ? { mime } : {}), + name: path.basename(canonicalSource), + size: stat.size, + }; + } catch (err) { + logger.warn(`quote cache: failed to register media path=${sourcePath}: ${String(err)}`); + return null; + } + } + + private requestGc(): void { + if (this.closed) return; + if (this.gcRunning) { + this.gcRequested = true; + return; + } + if (this.gcScheduled) return; + this.gcScheduled = true; + queueMicrotask(() => { + this.gcScheduled = false; + this.runGc(); + }); + } + + runGc(now = Date.now()): void { + if (this.closed || this.gcRunning) { + this.gcRequested = true; + return; + } + this.gcRunning = true; + try { + const messageCutoff = now - this.policy.retentionMs; + this.db.prepare("DELETE FROM quote_messages WHERE created_at < ?").run(messageCutoff); + + const accounts = this.db + .prepare("SELECT DISTINCT account_id FROM quote_messages") + .all() as Array<{ account_id: string }>; + for (const { account_id: accountId } of accounts) { + this.db + .prepare(` + DELETE FROM quote_messages + WHERE rowid IN ( + SELECT rowid FROM quote_messages + WHERE account_id = ? + ORDER BY created_at DESC, rowid DESC + LIMIT -1 OFFSET ? + ) + `) + .run(accountId, this.policy.maxMessagesPerAccount); + this.expireOldMedia(accountId, now - this.policy.mediaRetentionMs); + this.enforceMediaBudget(accountId); + } + this.pruneOrphanMediaFiles(); + } catch (err) { + logger.warn(`quote cache GC failed: ${String(err)}`); + } finally { + this.gcRunning = false; + if (this.gcRequested) { + this.gcRequested = false; + this.requestGc(); + } + } + } + + private listMedia(accountId: string): MediaRow[] { + return this.db + .prepare(` + SELECT media_path, MAX(COALESCE(media_size, 0)) AS media_size, + MAX(created_at) AS newest_at + FROM quote_messages + WHERE account_id = ? AND media_path IS NOT NULL + GROUP BY media_path + ORDER BY newest_at ASC + `) + .all(accountId) as MediaRow[]; + } + + private expireOldMedia(accountId: string, cutoff: number): void { + for (const media of this.listMedia(accountId)) { + if (media.newest_at >= cutoff) continue; + this.detachMedia(media.media_path); + } + } + + private enforceMediaBudget(accountId: string): void { + const rows = this.listMedia(accountId); + let total = rows.reduce((sum, row) => sum + Math.max(0, row.media_size), 0); + for (const row of rows) { + if (total <= this.policy.maxMediaBytesPerAccount) break; + this.detachMedia(row.media_path); + total -= Math.max(0, row.media_size); + } + } + + private detachMedia(mediaPath: string): void { + this.db + .prepare("UPDATE quote_messages SET media_path = NULL WHERE media_path = ?") + .run(mediaPath); + this.removeMediaIfOrphaned(mediaPath); + } + + private removeMediaIfOrphaned(mediaPath: string): void { + const row = this.db + .prepare("SELECT 1 AS found FROM quote_messages WHERE media_path = ? LIMIT 1") + .get(mediaPath) as { found?: number } | undefined; + if (row?.found) return; + try { + fs.unlinkSync(mediaPath); + } catch (err) { + if ((err as NodeJS.ErrnoException).code !== "ENOENT") { + logger.warn(`quote cache: failed to remove media path=${mediaPath}: ${String(err)}`); + } + } + } + + private pruneOrphanMediaFiles(): void { + if (!fs.existsSync(this.mediaRoot)) return; + const known = new Set( + ( + this.db + .prepare("SELECT DISTINCT media_path FROM quote_messages WHERE media_path IS NOT NULL") + .all() as Array<{ media_path: string }> + ).map((row) => row.media_path), + ); + const visit = (dir: string) => { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) visit(fullPath); + else if (entry.isFile() && !known.has(fullPath)) { + try { + fs.unlinkSync(fullPath); + } catch { + // retry during the next GC pass + } + } + } + }; + visit(this.mediaRoot); + } + + close(): void { + if (this.closed) return; + this.closed = true; + clearInterval(this.gcTimer); + this.db.close(); + } +} + +let activeStore: QuoteStore | null = null; +let initialization: Promise | null = null; +const activeAccounts = new Set(); + +export async function initializeQuoteStore( + cfg: OpenClawConfig, + accountId?: string, +): Promise { + if (accountId) activeAccounts.add(accountId); + const policy = resolveQuoteCachePolicy(cfg); + if (!policy.enabled) { + activeStore?.close(); + activeStore = null; + initialization = null; + return null; + } + if (activeStore) { + activeStore.updatePolicy(policy); + return activeStore; + } + if (!initialization) { + initialization = QuoteStore.open({ policy }).then((store) => { + activeStore = store; + return store; + }); + } + return initialization; +} + +export function getQuoteStore(): QuoteStore | null { + return activeStore; +} + +export function getActiveQuoteMediaSubdir(accountId: string): string | undefined { + return activeStore ? resolveQuoteMediaSubdir(accountId) : undefined; +} + +export function closeQuoteStore(): void { + activeStore?.close(); + activeStore = null; + initialization = null; + activeAccounts.clear(); +} + +export function deleteQuoteCacheForAccount(accountId: string): void { + if (activeStore) { + activeStore.deleteAccount(accountId); + return; + } + + const rootDir = path.join(resolveStateDir(), "openclaw-weixin"); + const mediaRoot = resolveQuoteMediaRoot(); + const dbPath = path.join(rootDir, "ref-messages.sqlite"); + if (!fs.existsSync(dbPath)) return; + try { + const require = createRequire(import.meta.url); + const sqlite = require("node:sqlite") as { DatabaseSync: DatabaseSyncConstructor }; + const db = new sqlite.DatabaseSync(dbPath); + db.prepare("DELETE FROM quote_messages WHERE account_id = ?").run(accountId); + db.close(); + fs.rmSync(path.join(mediaRoot, accountMediaDirName(accountId)), { + recursive: true, + force: true, + }); + fs.rmSync(path.join(rootDir, "ref-media", accountMediaDirName(accountId)), { + recursive: true, + force: true, + }); + } catch (err) { + logger.warn(`quote cache: failed to delete account=${accountId}: ${String(err)}`); + } +} + +export function deactivateQuoteStoreAccount(accountId: string): void { + activeAccounts.delete(accountId); + if (activeAccounts.size === 0) closeQuoteStore(); +} diff --git a/src/messaging/reply-progress-sender.ts b/src/messaging/reply-progress-sender.ts index a2069a1..b60f607 100644 --- a/src/messaging/reply-progress-sender.ts +++ b/src/messaging/reply-progress-sender.ts @@ -12,6 +12,7 @@ export type WeixinReplyProgressSenderDeps = { opts: WeixinApiOptions & { contextToken?: string; runId?: string; + accountId?: string; }; }; @@ -44,7 +45,7 @@ export class WeixinReplyProgressSender { this.runId = deps.runId; this.to = deps.to; this.accountId = deps.accountId; - this.opts = { ...deps.opts, runId: deps.runId }; + this.opts = { ...deps.opts, runId: deps.runId, accountId: deps.accountId }; } get replyOptions() { diff --git a/src/messaging/send-media.test.ts b/src/messaging/send-media.test.ts index 910f9cb..a5cfce3 100644 --- a/src/messaging/send-media.test.ts +++ b/src/messaging/send-media.test.ts @@ -87,6 +87,8 @@ describe("sendWeixinMediaFile", () => { fileName: "doc.pdf", uploaded: fakeUploaded, opts: baseParams.opts, + filePath: "/tmp/doc.pdf", + mediaMime: "application/pdf", }); }); diff --git a/src/messaging/send-media.ts b/src/messaging/send-media.ts index c838251..e6ddbb7 100644 --- a/src/messaging/send-media.ts +++ b/src/messaging/send-media.ts @@ -22,7 +22,7 @@ export async function sendWeixinMediaFile(params: { filePath: string; to: string; text: string; - opts: WeixinApiOptions & { contextToken?: string; runId?: string }; + opts: WeixinApiOptions & { contextToken?: string; runId?: string; accountId?: string }; cdnBaseUrl: string; }): Promise<{ messageId: string }> { const { filePath, to, text, opts, cdnBaseUrl } = params; @@ -40,7 +40,7 @@ export async function sendWeixinMediaFile(params: { logger.info( `[weixin] sendWeixinMediaFile: video upload done filekey=${uploaded.filekey} size=${uploaded.fileSize}`, ); - return sendVideoMessageWeixin({ to, text, uploaded, opts }); + return sendVideoMessageWeixin({ to, text, uploaded, opts, filePath, mediaMime: mime }); } if (mime.startsWith("image/")) { @@ -54,7 +54,7 @@ export async function sendWeixinMediaFile(params: { logger.info( `[weixin] sendWeixinMediaFile: image upload done filekey=${uploaded.filekey} size=${uploaded.fileSize}`, ); - return sendImageMessageWeixin({ to, text, uploaded, opts }); + return sendImageMessageWeixin({ to, text, uploaded, opts, filePath, mediaMime: mime }); } // File attachment: pdf, doc, zip, etc. @@ -72,5 +72,5 @@ export async function sendWeixinMediaFile(params: { logger.info( `[weixin] sendWeixinMediaFile: file upload done filekey=${uploaded.filekey} size=${uploaded.fileSize}`, ); - return sendFileMessageWeixin({ to, text, fileName, uploaded, opts }); + return sendFileMessageWeixin({ to, text, fileName, uploaded, opts, filePath, mediaMime: mime }); } diff --git a/src/messaging/send.test.ts b/src/messaging/send.test.ts index 7cbad70..8e2dbfb 100644 --- a/src/messaging/send.test.ts +++ b/src/messaging/send.test.ts @@ -9,7 +9,8 @@ vi.mock("../util/logger.js", () => ({ }, })); -const { mockSendMessageApi } = vi.hoisted(() => ({ +const { mockQuotePut, mockSendMessageApi } = vi.hoisted(() => ({ + mockQuotePut: vi.fn(), mockSendMessageApi: vi.fn(), })); @@ -17,24 +18,16 @@ vi.mock("../api/api.js", () => ({ sendMessage: mockSendMessageApi, })); +vi.mock("./quote-store.js", () => ({ + getQuoteStore: () => ({ put: mockQuotePut }), +})); + vi.mock("node:crypto", () => ({ default: { randomBytes: vi.fn(() => Buffer.from("deadbeef", "hex")), }, })); -vi.mock("openclaw/plugin-sdk", () => ({ - stripMarkdown: (text: string) => - text - .replace(/\*\*([^*]+)\*\*/g, "$1") - .replace(/\*([^*]+)\*/g, "$1") - .replace(/_([^_]+)_/g, "$1") - .replace(/~~([^~]+)~~/g, "$1") - .replace(/^#{1,6}\s+/gm, "") - .replace(/^[*-]\s+/gm, "") - .replace(/^\d+\.\s+/gm, ""), -})); - import { sendMessageWeixin, sendMessageItemWeixin, @@ -108,6 +101,38 @@ describe("sendMessageWeixin", () => { }), ).rejects.toThrow("api fail"); }); + + it("stores outbound text under the lossless server ID", async () => { + mockSendMessageApi.mockResolvedValueOnce({ message_id: "18446744073709551615" }); + const result = await sendMessageWeixin({ + to: "user1", + text: "hello", + opts: { baseUrl: "https://api.com", accountId: "account1" }, + }); + expect(result.serverMessageId).toBe("18446744073709551615"); + expect(result.messageId).not.toBe(result.serverMessageId); + expect(mockQuotePut).toHaveBeenCalledWith( + expect.objectContaining({ + accountId: "account1", + conversationId: "user1", + messageId: "18446744073709551615", + body: "hello", + direction: "outbound", + }), + ); + }); + + it("does not turn a successful send into a failure when caching fails", async () => { + mockSendMessageApi.mockResolvedValueOnce({ message_id: "99" }); + mockQuotePut.mockRejectedValueOnce(new Error("disk full")); + await expect( + sendMessageWeixin({ + to: "user1", + text: "hello", + opts: { baseUrl: "https://api.com", accountId: "account1" }, + }), + ).resolves.toMatchObject({ serverMessageId: "99" }); + }); }); describe("sendMessageItemWeixin", () => { @@ -138,6 +163,44 @@ describe("sendMessageItemWeixin", () => { }, ]); }); + + it("caches a structured text item and preserves an explicit client ID", async () => { + mockSendMessageApi.mockResolvedValueOnce({ message_id: "123" }); + const result = await sendMessageItemWeixin({ + to: "user1", + item: { type: MessageItemType.TEXT, text_item: { text: "structured text" } }, + opts: { baseUrl: "https://api.com", accountId: "account1" }, + clientId: "explicit-client-id", + }); + expect(result).toEqual({ messageId: "explicit-client-id", serverMessageId: "123" }); + expect(mockQuotePut).toHaveBeenCalledWith( + expect.objectContaining({ + messageId: "123", + body: "structured text", + }), + ); + }); + + it("returns the client ID when a structured item has no server ID", async () => { + mockSendMessageApi.mockResolvedValueOnce({}); + const result = await sendMessageItemWeixin({ + to: "user1", + item: { type: MessageItemType.TEXT, text_item: {} }, + opts: { baseUrl: "https://api.com" }, + }); + expect(result.serverMessageId).toBeUndefined(); + }); + + it("rethrows structured-item API errors", async () => { + mockSendMessageApi.mockRejectedValueOnce(new Error("structured fail")); + await expect( + sendMessageItemWeixin({ + to: "user1", + item: { type: MessageItemType.TEXT, text_item: { text: "hello" } }, + opts: { baseUrl: "https://api.com" }, + }), + ).rejects.toThrow("structured fail"); + }); }); function makeUploadedFileInfo(overrides?: Partial): UploadedFileInfo { @@ -224,6 +287,27 @@ describe("sendImageMessageWeixin", () => { }), ).rejects.toThrow("cdn fail"); }); + + it("stores managed metadata for an outbound image", async () => { + mockSendMessageApi.mockResolvedValueOnce({ message_id: "image-server-id" }); + await sendImageMessageWeixin({ + to: "user1", + text: "", + uploaded: makeUploadedFileInfo(), + opts: { baseUrl: "https://api.com", accountId: "account1" }, + filePath: "/tmp/photo.png", + mediaMime: "image/png", + }); + expect(mockQuotePut).toHaveBeenCalledWith( + expect.objectContaining({ + messageId: "image-server-id", + body: "[图片]", + sourceMediaPath: "/tmp/photo.png", + mediaMime: "image/png", + mediaName: "photo.png", + }), + ); + }); }); describe("sendVideoMessageWeixin", () => { diff --git a/src/messaging/send.ts b/src/messaging/send.ts index 8d1a50f..0aaea1b 100644 --- a/src/messaging/send.ts +++ b/src/messaging/send.ts @@ -7,14 +7,48 @@ import { generateId } from "../util/random.js"; import type { MessageItem, SendMessageReq } from "../api/types.js"; import { MessageItemType, MessageState, MessageType } from "../api/types.js"; import type { UploadedFileInfo } from "../cdn/upload.js"; +import { getMediaLabel } from "./inbound.js"; +import { getQuoteStore } from "./quote-store.js"; export { StreamingMarkdownFilter } from "./markdown-filter.js"; type WeixinMessageSendOptions = WeixinApiOptions & { contextToken?: string; runId?: string; + accountId?: string; }; +type WeixinSendResult = { messageId: string; serverMessageId?: string }; + +async function cacheOutboundMessage(params: { + opts: WeixinMessageSendOptions; + to: string; + serverMessageId?: string; + body: string; + sourceMediaPath?: string; + mediaMime?: string; + mediaName?: string; +}): Promise { + if (!params.opts.accountId || !params.serverMessageId) return; + try { + await getQuoteStore()?.put({ + accountId: params.opts.accountId, + conversationId: params.to, + messageId: params.serverMessageId, + direction: "outbound", + body: params.body, + ...(params.sourceMediaPath ? { sourceMediaPath: params.sourceMediaPath } : {}), + ...(params.mediaMime ? { mediaMime: params.mediaMime } : {}), + ...(params.mediaName ? { mediaName: params.mediaName } : {}), + createdAt: Date.now(), + }); + } catch (err) { + logger.warn( + `quote cache: failed to save outbound message id=${params.serverMessageId}: ${String(err)}`, + ); + } +} + function generateClientId(): string { return generateId("openclaw-weixin"); } @@ -70,7 +104,7 @@ export async function sendMessageWeixin(params: { to: string; text: string; opts: WeixinMessageSendOptions; -}): Promise<{ messageId: string }> { +}): Promise { const { to, text, opts } = params; if (!opts.contextToken) { logger.warn(`sendMessageWeixin: contextToken missing for to=${to}, sending without context`); @@ -84,17 +118,22 @@ export async function sendMessageWeixin(params: { clientId, }); try { - await sendMessageApi({ + const response = await sendMessageApi({ baseUrl: opts.baseUrl, token: opts.token, timeoutMs: opts.timeoutMs, body: req, }); + const serverMessageId = response?.message_id; + await cacheOutboundMessage({ opts, to, serverMessageId, body: text }); + return { + messageId: clientId, + ...(serverMessageId ? { serverMessageId } : {}), + }; } catch (err) { logger.error(`sendMessageWeixin: failed to=${to} clientId=${clientId} err=${String(err)}`); throw err; } - return { messageId: clientId }; } /** Send a single structured MessageItem downstream. */ @@ -104,7 +143,7 @@ export async function sendMessageItemWeixin(params: { opts: WeixinMessageSendOptions; clientId?: string; label?: string; -}): Promise<{ messageId: string }> { +}): Promise { const { to, item, opts } = params; if (!opts.contextToken) { logger.warn( @@ -125,19 +164,25 @@ export async function sendMessageItemWeixin(params: { }, }; try { - await sendMessageApi({ + const response = await sendMessageApi({ baseUrl: opts.baseUrl, token: opts.token, timeoutMs: opts.timeoutMs, body: req, }); + const serverMessageId = response?.message_id; + const itemText = item.type === MessageItemType.TEXT ? (item.text_item?.text ?? "") : ""; + if (itemText) await cacheOutboundMessage({ opts, to, serverMessageId, body: itemText }); + return { + messageId: clientId, + ...(serverMessageId ? { serverMessageId } : {}), + }; } catch (err) { logger.error( `${params.label ?? "sendMessageItemWeixin"}: failed to=${to} clientId=${clientId} err=${String(err)}`, ); throw err; } - return { messageId: clientId }; } /** @@ -150,7 +195,10 @@ async function sendMediaItems(params: { mediaItem: MessageItem; opts: WeixinMessageSendOptions; label: string; -}): Promise<{ messageId: string }> { + sourceMediaPath?: string; + mediaMime?: string; + mediaName?: string; +}): Promise { const { to, text, mediaItem, opts, label } = params; const runId = opts.runId; @@ -161,6 +209,7 @@ async function sendMediaItems(params: { items.push(mediaItem); let lastClientId = ""; + let lastServerMessageId: string | undefined; for (const item of items) { lastClientId = generateClientId(); const req: SendMessageReq = { @@ -176,12 +225,31 @@ async function sendMediaItems(params: { }, }; try { - await sendMessageApi({ + const response = await sendMessageApi({ baseUrl: opts.baseUrl, token: opts.token, timeoutMs: opts.timeoutMs, body: req, }); + lastServerMessageId = response?.message_id; + if (item.type === MessageItemType.TEXT) { + await cacheOutboundMessage({ + opts, + to, + serverMessageId: lastServerMessageId, + body: item.text_item?.text ?? text, + }); + } else { + await cacheOutboundMessage({ + opts, + to, + serverMessageId: lastServerMessageId, + body: getMediaLabel(item.type), + sourceMediaPath: params.sourceMediaPath, + mediaMime: params.mediaMime, + mediaName: params.mediaName, + }); + } } catch (err) { logger.error(`${label}: failed to=${to} clientId=${lastClientId} err=${String(err)}`); throw err; @@ -189,7 +257,10 @@ async function sendMediaItems(params: { } logger.info(`${label}: success to=${to} clientId=${lastClientId}`); - return { messageId: lastClientId }; + return { + messageId: lastClientId, + ...(lastServerMessageId ? { serverMessageId: lastServerMessageId } : {}), + }; } /** @@ -206,7 +277,9 @@ export async function sendImageMessageWeixin(params: { text: string; uploaded: UploadedFileInfo; opts: WeixinMessageSendOptions; -}): Promise<{ messageId: string }> { + filePath?: string; + mediaMime?: string; +}): Promise { const { to, text, uploaded, opts } = params; if (!opts.contextToken) { logger.warn( @@ -229,7 +302,16 @@ export async function sendImageMessageWeixin(params: { }, }; - return sendMediaItems({ to, text, mediaItem: imageItem, opts, label: "sendImageMessageWeixin" }); + return sendMediaItems({ + to, + text, + mediaItem: imageItem, + opts, + label: "sendImageMessageWeixin", + sourceMediaPath: params.filePath, + mediaMime: params.mediaMime, + mediaName: params.filePath?.split(/[\\/]/).pop(), + }); } /** @@ -242,7 +324,9 @@ export async function sendVideoMessageWeixin(params: { text: string; uploaded: UploadedFileInfo; opts: WeixinMessageSendOptions; -}): Promise<{ messageId: string }> { + filePath?: string; + mediaMime?: string; +}): Promise { const { to, text, uploaded, opts } = params; if (!opts.contextToken) { logger.warn( @@ -262,7 +346,16 @@ export async function sendVideoMessageWeixin(params: { }, }; - return sendMediaItems({ to, text, mediaItem: videoItem, opts, label: "sendVideoMessageWeixin" }); + return sendMediaItems({ + to, + text, + mediaItem: videoItem, + opts, + label: "sendVideoMessageWeixin", + sourceMediaPath: params.filePath, + mediaMime: params.mediaMime, + mediaName: params.filePath?.split(/[\\/]/).pop(), + }); } /** @@ -276,7 +369,9 @@ export async function sendFileMessageWeixin(params: { fileName: string; uploaded: UploadedFileInfo; opts: WeixinMessageSendOptions; -}): Promise<{ messageId: string }> { + filePath?: string; + mediaMime?: string; +}): Promise { const { to, text, fileName, uploaded, opts } = params; if (!opts.contextToken) { logger.warn( @@ -296,5 +391,14 @@ export async function sendFileMessageWeixin(params: { }, }; - return sendMediaItems({ to, text, mediaItem: fileItem, opts, label: "sendFileMessageWeixin" }); + return sendMediaItems({ + to, + text, + mediaItem: fileItem, + opts, + label: "sendFileMessageWeixin", + sourceMediaPath: params.filePath, + mediaMime: params.mediaMime, + mediaName: fileName, + }); } diff --git a/src/messaging/slash-commands.ts b/src/messaging/slash-commands.ts index e20f56d..5cde974 100644 --- a/src/messaging/slash-commands.ts +++ b/src/messaging/slash-commands.ts @@ -28,10 +28,11 @@ export interface SlashCommandContext { /** 发送回复消息 */ async function sendReply(ctx: SlashCommandContext, text: string): Promise { - const opts: WeixinApiOptions & { contextToken?: string } = { + const opts: WeixinApiOptions & { contextToken?: string; accountId?: string } = { baseUrl: ctx.baseUrl, token: ctx.token, contextToken: ctx.contextToken, + accountId: ctx.accountId, }; await sendMessageWeixin({ to: ctx.to, text, opts }); } diff --git a/src/storage/sync-buf.test.ts b/src/storage/sync-buf.test.ts index aac398d..d1676d4 100644 --- a/src/storage/sync-buf.test.ts +++ b/src/storage/sync-buf.test.ts @@ -3,6 +3,8 @@ import fs from "node:fs"; import path from "node:path"; import os from "node:os"; +import * as syncBuf from "./sync-buf.js"; + vi.mock("../util/logger.js", () => ({ logger: { info: vi.fn(), @@ -25,8 +27,7 @@ afterEach(() => { }); async function loadModule() { - vi.resetModules(); - return await import("./sync-buf.js"); + return syncBuf; } describe("getSyncBufFilePath", () => {