{"owner":"7Sageer","repo":"sublink-worker","hasSkills":true,"totalSkillsCount":2,"totalTokensCount":3457,"categories":["claude-rule","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":["CLAUDE.md","AGENTS.md"],"skills":{"CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## 协作偏好\n\n- 用中文回复；代码注释用英文，注释写 why 不写 how。\n- 简洁直接，不要多余总结和解释；除非存在高风险或信息缺口，直接写代码。\n- 函数式优先，TS/JS 中避免 OOP；新功能优先复用或重构现有代码。\n- 遵循 KISS、DRY 和 `ai-coding-discipline` 规则。\n- 从第一性原理解构问题，警惕 XY 问题；发现不合理方向立即指出，不奉承。\n- 架构权衡参考 `ddia-principles` 和 `software-design-philosophy`。\n\n## 项目概览\n\nSublink Worker 是多平台代理订阅转换器：将各类协议（ShadowSocks/VMess/VLESS/Hysteria2/Trojan/TUIC）转为客户端配置（Sing-Box/Clash/Xray/Surge）。同一份代码跑在 Cloudflare Workers / Node.js / Vercel / Docker 上。技术栈：Hono（Web/JSX SSR）+ Vitest + Wrangler + esbuild + ioredis。\n\n## 常用命令\n\n- `npm run dev` — Wrangler 本地开发（Cloudflare Workers 入口）\n- `npm run dev:node` — esbuild bundle + 启动 Node.js server（Docker 同此入口）\n- `npm test` — Vitest（基于 `@cloudflare/vitest-pool-workers`，依赖 `wrangler.toml`）\n- `npx vitest test/<file>.test.js` — 跑单个测试文件\n- `npm run build` — Vercel 构建（输出到 `dist/vercel/`）\n- `npm run deploy` — `setup-kv` + `wrangler deploy`\n\n无 ESLint/Prettier/Biome 配置，未启用自动格式化。\n\n## 多运行时架构\n\n入口分平台：`src/worker.jsx`（Cloudflare）、`src/platforms/node-server.js`（Node/Docker）、`api/index.js`（Vercel）。三者都通过 `createApp(runtime)`（`src/app/createApp.jsx`）创建同一个 Hono app。\n\n- `src/runtime/{cloudflare,node,vercel}.js` 提供平台适配\n- `src/runtime/runtimeConfig.js` 规范化 KV、资源获取、日志、环境变量默认值\n\n新增运行时：在 `src/runtime/` 加 adapter，按需在 `src/adapters/kv/` 加 KV 实现，按需在 `src/platforms/` 加入口。\n\n## KV 存储抽象\n\n统一接口：`get(key)`、`put(key, value, options)`、`delete(key)`。实现：`CloudflareKVAdapter`、`RedisKVAdapter`（ioredis）、`UpstashKVAdapter`（REST）、`MemoryKVAdapter`。\n\n- 服务层：`ShortLinkService`（短链）、`ConfigStorageService`（base config 存储，默认 30 天 TTL）\n- Node/Vercel 优先级：Redis > Upstash/Vercel KV > 内存兜底；`DISABLE_MEMORY_KV=true` 关闭兜底\n- Cloudflare 用 `wrangler.toml` 的 `SUBLINK_KV` 与 `ASSETS` binding\n\n环境变量：`REDIS_URL` / `REDIS_HOST`+`REDIS_PORT` / `REDIS_USERNAME` / `REDIS_PASSWORD` / `REDIS_TLS` / `REDIS_KEY_PREFIX`、`KV_REST_API_URL`+`KV_REST_API_TOKEN`、`CONFIG_TTL_SECONDS`、`SHORT_LINK_TTL_SECONDS`、`STATIC_DIR`、`PORT`。\n\n## 协议解析与配置构建\n\n**ProxyParser**（`src/parsers/ProxyParser.js`）按 URL scheme 分发到 `src/parsers/protocols/<protocol>Parser.js`。HTTP(S) 订阅走 `httpSubscriptionFetcher` → `subscriptionContentParser`，自动识别 Sing-Box JSON / Clash YAML / Surge INI / Base64 列表。\n\n返回值约定：\n- 协议 parser：`{ tag, type, ...protocolFields }`\n- 订阅级 parser：`{ type: 'yamlConfig'|'singboxConfig'|'surgeConfig', config, proxies }`\n\n**新增协议**：在 `src/parsers/protocols/` 加 parser，并在 `ProxyParser.js` 的 `protocolParsers` map 注册。\n\n**Builder 模式**：`SingboxConfigBuilder` / `ClashConfigBuilder` / `SurgeConfigBuilder` 都继承 `BaseConfigBuilder`。子类必须实现：`getProxies()`、`getProxyName(proxy)`、`convertProxy(proxy)`、`addProxyToConfig(proxy)`、`addAutoSelectGroup(list)`、`addNodeSelectGroup(list)`、`addOutboundGroups(outbounds, list)`、`addCustomRuleGroups(list)`、`addFallBackGroup(list)`、`addCountryGroups()`、`formatConfig()`。\n\n**Config Override**：订阅含完整配置时，`applyConfigOverrides()` 合并非代理字段到 base config；blacklist（proxies、rules、rule-providers）永远不被覆盖；Clash `proxy-groups` 可被订阅覆盖以保留用户分组结构。\n\n国家分组逻辑在 `src/utils.js#groupProxiesByCountry`。\n\n## 测试\n\nVitest + `@cloudflare/vitest-pool-workers`，配置 `vitest.config.js` 指向 `wrangler.toml`。测试文件在 `test/`。\n\n- 写测试时用 `MemoryKVAdapter` 做 KV，用 `createApp(runtime)` 拿到可测的 Hono app\n- 覆盖：路由、各 builder、各 parser（含 YAML 订阅）、country grouping、selectedRules 向后兼容\n\n## 关键约定\n\n- `.jsx` 文件用 Hono JSX runtime，**不是 React**\n- Base64 输入用 `tryDecodeSubscriptionLines()` 处理（同时支持原文和 Base64）\n- 错误用 `ServiceError` 子类（`InvalidPayloadError`、`MissingDependencyError`），返回干净响应\n- i18n：zh-CN / en-US / fa-IR，文件在 `src/i18n/`\n\n## 本地工作流\n\n- 本地分层规划放 `.roadmap/roadmap.md`（已 `.gitignore`）；更新前先同步 GitHub open issues，每条记录留 issue 链接、优先级依据、下一步\n- 个人偏好、沙盒、临时上下文写入 `CLAUDE.local.md`（不提交）\n- 通用 agent 规则放 `AGENTS.md` / `AGENTS.local.md`\n- Claude 本地设置写入 `.claude/settings.local.json`（不提交）\n\n## 文档参考\n\n代理工具配置问题查官方文档：\n- sing-box: https://sing-box.sagernet.org/\n- clash/mihomo: https://wiki.metacubex.one/\n- surge: https://blankwonder.gitbooks.io/surge-manual/content/\n- xray: https://xtls.github.io/config/\n","AGENTS.md":"# AGENTS.md\n\n## 协作偏好\n\n- 用中文回复；代码注释用英文，注释写 why 不写 how。\n- 简洁直接，不要多余总结和解释；除非存在高风险或信息缺口，直接写代码。\n- 函数式优先，TS/JS 中避免 OOP；新功能优先复用或重构现有代码。\n- 遵循 KISS、DRY 原则；从第一性原理解构问题，警惕 XY 问题。\n- 发现不合理的需求或方向要立即指出，不奉承。\n\n## 项目概览\n\nSublink Worker 是多平台代理订阅转换器：将各类协议（ShadowSocks/VMess/VLESS/Hysteria2/Trojan/TUIC）转为客户端配置（Sing-Box/Clash/Xray/Surge）。同一份代码跑在 Cloudflare Workers / Node.js / Vercel / Docker 上。技术栈：Hono（Web/JSX SSR）+ Vitest + Wrangler + esbuild + ioredis。\n\n## 常用命令\n\n- `npm run dev` — Wrangler 本地开发（Cloudflare Workers 入口）\n- `npm run dev:node` — esbuild bundle + 启动 Node.js server\n- `npm test` — Vitest（基于 `@cloudflare/vitest-pool-workers`，依赖 `wrangler.toml`）\n- `npx vitest test/<file>.test.js` — 跑单个测试文件\n- `npm run build` — Vercel 构建（输出到 `dist/vercel/`）\n- `npm run deploy` — `setup-kv` + `wrangler deploy`\n\n无 ESLint/Prettier/Biome 配置，未启用自动格式化。\n\n## 多运行时架构\n\n入口分平台：`src/worker.jsx`（Cloudflare）、`src/platforms/node-server.js`（Node/Docker）、`api/index.js`（Vercel）。三者都通过 `createApp(runtime)`（`src/app/createApp.jsx`）创建同一个 Hono app。\n\n- `src/runtime/{cloudflare,node,vercel}.js` 提供平台适配\n- `src/runtime/runtimeConfig.js` 规范化 KV、资源获取、日志、环境变量默认值\n\n新增运行时：在 `src/runtime/` 加 adapter，按需在 `src/adapters/kv/` 加 KV 实现，按需在 `src/platforms/` 加入口。\n\n## KV 存储抽象\n\n统一接口：`get(key)`、`put(key, value, options)`、`delete(key)`。实现：`CloudflareKVAdapter`、`RedisKVAdapter`（ioredis）、`UpstashKVAdapter`（REST）、`MemoryKVAdapter`。\n\n- 服务层：`ShortLinkService`（短链）、`ConfigStorageService`（base config 存储，默认 30 天 TTL）\n- Node/Vercel 优先级：Redis > Upstash/Vercel KV > 内存兜底；`DISABLE_MEMORY_KV=true` 关闭兜底\n- Cloudflare 用 `wrangler.toml` 的 `SUBLINK_KV` 与 `ASSETS` binding\n\n环境变量：`REDIS_URL` / `REDIS_HOST`+`REDIS_PORT` / `REDIS_USERNAME` / `REDIS_PASSWORD` / `REDIS_TLS` / `REDIS_KEY_PREFIX`、`KV_REST_API_URL`+`KV_REST_API_TOKEN`、`CONFIG_TTL_SECONDS`、`SHORT_LINK_TTL_SECONDS`、`STATIC_DIR`、`PORT`。\n\n## 协议解析与配置构建\n\n**ProxyParser**（`src/parsers/ProxyParser.js`）按 URL scheme 分发到 `src/parsers/protocols/<protocol>Parser.js`。HTTP(S) 订阅走 `httpSubscriptionFetcher` → `subscriptionContentParser`，自动识别 Sing-Box JSON / Clash YAML / Surge INI / Base64 列表。\n\n返回值约定：\n- 协议 parser：`{ tag, type, ...protocolFields }`\n- 订阅级 parser：`{ type: 'yamlConfig'|'singboxConfig'|'surgeConfig', config, proxies }`\n\n**新增协议**：在 `src/parsers/protocols/` 加 parser，并在 `ProxyParser.js` 的 `protocolParsers` map 注册。\n\n**Builder 模式**：`SingboxConfigBuilder` / `ClashConfigBuilder` / `SurgeConfigBuilder` 都继承 `BaseConfigBuilder`。子类必须实现：`getProxies()`、`getProxyName(proxy)`、`convertProxy(proxy)`、`addProxyToConfig(proxy)`、`addAutoSelectGroup(list)`、`addNodeSelectGroup(list)`、`addOutboundGroups(outbounds, list)`、`addCustomRuleGroups(list)`、`addFallBackGroup(list)`、`addCountryGroups()`、`formatConfig()`。\n\n**Config Override**：订阅含完整配置时，`applyConfigOverrides()` 合并非代理字段到 base config；blacklist（proxies、rules、rule-providers）永远不被覆盖；Clash `proxy-groups` 可被订阅覆盖以保留用户分组结构。\n\n国家分组逻辑在 `src/utils.js#groupProxiesByCountry`。\n\n## 测试\n\nVitest + `@cloudflare/vitest-pool-workers`，配置 `vitest.config.js` 指向 `wrangler.toml`。测试文件在 `test/`。\n\n- 写测试时用 `MemoryKVAdapter` 做 KV，用 `createApp(runtime)` 拿到可测的 Hono app\n- 覆盖：路由、各 builder、各 parser（含 YAML 订阅）、country grouping、selectedRules 向后兼容\n\n## 关键约定\n\n- `.jsx` 文件用 Hono JSX runtime，**不是 React**\n- Base64 输入用 `tryDecodeSubscriptionLines()` 处理（同时支持原文和 Base64）\n- 错误用 `ServiceError` 子类（`InvalidPayloadError`、`MissingDependencyError`），返回干净响应\n- i18n：zh-CN / en-US / fa-IR，文件在 `src/i18n/`\n\n## 本地工作流\n\n- 本地分层规划放 `.roadmap/roadmap.md`（已 `.gitignore`）；更新前先同步 GitHub open issues\n- 个人偏好、沙盒、临时上下文写入 `AGENTS.local.md`（不提交）\n- Claude 共享规则放 `CLAUDE.md`，个人覆盖放 `CLAUDE.local.md`\n\n## 文档参考\n\n代理工具配置问题查官方文档：\n- sing-box: https://sing-box.sagernet.org/\n- clash/mihomo: https://wiki.metacubex.one/\n- surge: https://blankwonder.gitbooks.io/surge-manual/content/\n- xray: https://xtls.github.io/config/\n"},"files":{"CLAUDE.md":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## 协作偏好\n\n- 用中文回复；代码注释用英文，注释写 why 不写 how。\n- 简洁直接，不要多余总结和解释；除非存在高风险或信息缺口，直接写代码。\n- 函数式优先，TS/JS 中避免 OOP；新功能优先复用或重构现有代码。\n- 遵循 KISS、DRY 和 `ai-coding-discipline` 规则。\n- 从第一性原理解构问题，警惕 XY 问题；发现不合理方向立即指出，不奉承。\n- 架构权衡参考 `ddia-principles` 和 `software-design-philosophy`。\n\n## 项目概览\n\nSublink Worker 是多平台代理订阅转换器：将各类协议（ShadowSocks/VMess/VLESS/Hysteria2/Trojan/TUIC）转为客户端配置（Sing-Box/Clash/Xray/Surge）。同一份代码跑在 Cloudflare Workers / Node.js / Vercel / Docker 上。技术栈：Hono（Web/JSX SSR）+ Vitest + Wrangler + esbuild + ioredis。\n\n## 常用命令\n\n- `npm run dev` — Wrangler 本地开发（Cloudflare Workers 入口）\n- `npm run dev:node` — esbuild bundle + 启动 Node.js server（Docker 同此入口）\n- `npm test` — Vitest（基于 `@cloudflare/vitest-pool-workers`，依赖 `wrangler.toml`）\n- `npx vitest test/<file>.test.js` — 跑单个测试文件\n- `npm run build` — Vercel 构建（输出到 `dist/vercel/`）\n- `npm run deploy` — `setup-kv` + `wrangler deploy`\n\n无 ESLint/Prettier/Biome 配置，未启用自动格式化。\n\n## 多运行时架构\n\n入口分平台：`src/worker.jsx`（Cloudflare）、`src/platforms/node-server.js`（Node/Docker）、`api/index.js`（Vercel）。三者都通过 `createApp(runtime)`（`src/app/createApp.jsx`）创建同一个 Hono app。\n\n- `src/runtime/{cloudflare,node,vercel}.js` 提供平台适配\n- `src/runtime/runtimeConfig.js` 规范化 KV、资源获取、日志、环境变量默认值\n\n新增运行时：在 `src/runtime/` 加 adapter，按需在 `src/adapters/kv/` 加 KV 实现，按需在 `src/platforms/` 加入口。\n\n## KV 存储抽象\n\n统一接口：`get(key)`、`put(key, value, options)`、`delete(key)`。实现：`CloudflareKVAdapter`、`RedisKVAdapter`（ioredis）、`UpstashKVAdapter`（REST）、`MemoryKVAdapter`。\n\n- 服务层：`ShortLinkService`（短链）、`ConfigStorageService`（base config 存储，默认 30 天 TTL）\n- Node/Vercel 优先级：Redis > Upstash/Vercel KV > 内存兜底；`DISABLE_MEMORY_KV=true` 关闭兜底\n- Cloudflare 用 `wrangler.toml` 的 `SUBLINK_KV` 与 `ASSETS` binding\n\n环境变量：`REDIS_URL` / `REDIS_HOST`+`REDIS_PORT` / `REDIS_USERNAME` / `REDIS_PASSWORD` / `REDIS_TLS` / `REDIS_KEY_PREFIX`、`KV_REST_API_URL`+`KV_REST_API_TOKEN`、`CONFIG_TTL_SECONDS`、`SHORT_LINK_TTL_SECONDS`、`STATIC_DIR`、`PORT`。\n\n## 协议解析与配置构建\n\n**ProxyParser**（`src/parsers/ProxyParser.js`）按 URL scheme 分发到 `src/parsers/protocols/<protocol>Parser.js`。HTTP(S) 订阅走 `httpSubscriptionFetcher` → `subscriptionContentParser`，自动识别 Sing-Box JSON / Clash YAML / Surge INI / Base64 列表。\n\n返回值约定：\n- 协议 parser：`{ tag, type, ...protocolFields }`\n- 订阅级 parser：`{ type: 'yamlConfig'|'singboxConfig'|'surgeConfig', config, proxies }`\n\n**新增协议**：在 `src/parsers/protocols/` 加 parser，并在 `ProxyParser.js` 的 `protocolParsers` map 注册。\n\n**Builder 模式**：`SingboxConfigBuilder` / `ClashConfigBuilder` / `SurgeConfigBuilder` 都继承 `BaseConfigBuilder`。子类必须实现：`getProxies()`、`getProxyName(proxy)`、`convertProxy(proxy)`、`addProxyToConfig(proxy)`、`addAutoSelectGroup(list)`、`addNodeSelectGroup(list)`、`addOutboundGroups(outbounds, list)`、`addCustomRuleGroups(list)`、`addFallBackGroup(list)`、`addCountryGroups()`、`formatConfig()`。\n\n**Config Override**：订阅含完整配置时，`applyConfigOverrides()` 合并非代理字段到 base config；blacklist（proxies、rules、rule-providers）永远不被覆盖；Clash `proxy-groups` 可被订阅覆盖以保留用户分组结构。\n\n国家分组逻辑在 `src/utils.js#groupProxiesByCountry`。\n\n## 测试\n\nVitest + `@cloudflare/vitest-pool-workers`，配置 `vitest.config.js` 指向 `wrangler.toml`。测试文件在 `test/`。\n\n- 写测试时用 `MemoryKVAdapter` 做 KV，用 `createApp(runtime)` 拿到可测的 Hono app\n- 覆盖：路由、各 builder、各 parser（含 YAML 订阅）、country grouping、selectedRules 向后兼容\n\n## 关键约定\n\n- `.jsx` 文件用 Hono JSX runtime，**不是 React**\n- Base64 输入用 `tryDecodeSubscriptionLines()` 处理（同时支持原文和 Base64）\n- 错误用 `ServiceError` 子类（`InvalidPayloadError`、`MissingDependencyError`），返回干净响应\n- i18n：zh-CN / en-US / fa-IR，文件在 `src/i18n/`\n\n## 本地工作流\n\n- 本地分层规划放 `.roadmap/roadmap.md`（已 `.gitignore`）；更新前先同步 GitHub open issues，每条记录留 issue 链接、优先级依据、下一步\n- 个人偏好、沙盒、临时上下文写入 `CLAUDE.local.md`（不提交）\n- 通用 agent 规则放 `AGENTS.md` / `AGENTS.local.md`\n- Claude 本地设置写入 `.claude/settings.local.json`（不提交）\n\n## 文档参考\n\n代理工具配置问题查官方文档：\n- sing-box: https://sing-box.sagernet.org/\n- clash/mihomo: https://wiki.metacubex.one/\n- surge: https://blankwonder.gitbooks.io/surge-manual/content/\n- xray: https://xtls.github.io/config/\n","AGENTS.md":"# AGENTS.md\n\n## 协作偏好\n\n- 用中文回复；代码注释用英文，注释写 why 不写 how。\n- 简洁直接，不要多余总结和解释；除非存在高风险或信息缺口，直接写代码。\n- 函数式优先，TS/JS 中避免 OOP；新功能优先复用或重构现有代码。\n- 遵循 KISS、DRY 原则；从第一性原理解构问题，警惕 XY 问题。\n- 发现不合理的需求或方向要立即指出，不奉承。\n\n## 项目概览\n\nSublink Worker 是多平台代理订阅转换器：将各类协议（ShadowSocks/VMess/VLESS/Hysteria2/Trojan/TUIC）转为客户端配置（Sing-Box/Clash/Xray/Surge）。同一份代码跑在 Cloudflare Workers / Node.js / Vercel / Docker 上。技术栈：Hono（Web/JSX SSR）+ Vitest + Wrangler + esbuild + ioredis。\n\n## 常用命令\n\n- `npm run dev` — Wrangler 本地开发（Cloudflare Workers 入口）\n- `npm run dev:node` — esbuild bundle + 启动 Node.js server\n- `npm test` — Vitest（基于 `@cloudflare/vitest-pool-workers`，依赖 `wrangler.toml`）\n- `npx vitest test/<file>.test.js` — 跑单个测试文件\n- `npm run build` — Vercel 构建（输出到 `dist/vercel/`）\n- `npm run deploy` — `setup-kv` + `wrangler deploy`\n\n无 ESLint/Prettier/Biome 配置，未启用自动格式化。\n\n## 多运行时架构\n\n入口分平台：`src/worker.jsx`（Cloudflare）、`src/platforms/node-server.js`（Node/Docker）、`api/index.js`（Vercel）。三者都通过 `createApp(runtime)`（`src/app/createApp.jsx`）创建同一个 Hono app。\n\n- `src/runtime/{cloudflare,node,vercel}.js` 提供平台适配\n- `src/runtime/runtimeConfig.js` 规范化 KV、资源获取、日志、环境变量默认值\n\n新增运行时：在 `src/runtime/` 加 adapter，按需在 `src/adapters/kv/` 加 KV 实现，按需在 `src/platforms/` 加入口。\n\n## KV 存储抽象\n\n统一接口：`get(key)`、`put(key, value, options)`、`delete(key)`。实现：`CloudflareKVAdapter`、`RedisKVAdapter`（ioredis）、`UpstashKVAdapter`（REST）、`MemoryKVAdapter`。\n\n- 服务层：`ShortLinkService`（短链）、`ConfigStorageService`（base config 存储，默认 30 天 TTL）\n- Node/Vercel 优先级：Redis > Upstash/Vercel KV > 内存兜底；`DISABLE_MEMORY_KV=true` 关闭兜底\n- Cloudflare 用 `wrangler.toml` 的 `SUBLINK_KV` 与 `ASSETS` binding\n\n环境变量：`REDIS_URL` / `REDIS_HOST`+`REDIS_PORT` / `REDIS_USERNAME` / `REDIS_PASSWORD` / `REDIS_TLS` / `REDIS_KEY_PREFIX`、`KV_REST_API_URL`+`KV_REST_API_TOKEN`、`CONFIG_TTL_SECONDS`、`SHORT_LINK_TTL_SECONDS`、`STATIC_DIR`、`PORT`。\n\n## 协议解析与配置构建\n\n**ProxyParser**（`src/parsers/ProxyParser.js`）按 URL scheme 分发到 `src/parsers/protocols/<protocol>Parser.js`。HTTP(S) 订阅走 `httpSubscriptionFetcher` → `subscriptionContentParser`，自动识别 Sing-Box JSON / Clash YAML / Surge INI / Base64 列表。\n\n返回值约定：\n- 协议 parser：`{ tag, type, ...protocolFields }`\n- 订阅级 parser：`{ type: 'yamlConfig'|'singboxConfig'|'surgeConfig', config, proxies }`\n\n**新增协议**：在 `src/parsers/protocols/` 加 parser，并在 `ProxyParser.js` 的 `protocolParsers` map 注册。\n\n**Builder 模式**：`SingboxConfigBuilder` / `ClashConfigBuilder` / `SurgeConfigBuilder` 都继承 `BaseConfigBuilder`。子类必须实现：`getProxies()`、`getProxyName(proxy)`、`convertProxy(proxy)`、`addProxyToConfig(proxy)`、`addAutoSelectGroup(list)`、`addNodeSelectGroup(list)`、`addOutboundGroups(outbounds, list)`、`addCustomRuleGroups(list)`、`addFallBackGroup(list)`、`addCountryGroups()`、`formatConfig()`。\n\n**Config Override**：订阅含完整配置时，`applyConfigOverrides()` 合并非代理字段到 base config；blacklist（proxies、rules、rule-providers）永远不被覆盖；Clash `proxy-groups` 可被订阅覆盖以保留用户分组结构。\n\n国家分组逻辑在 `src/utils.js#groupProxiesByCountry`。\n\n## 测试\n\nVitest + `@cloudflare/vitest-pool-workers`，配置 `vitest.config.js` 指向 `wrangler.toml`。测试文件在 `test/`。\n\n- 写测试时用 `MemoryKVAdapter` 做 KV，用 `createApp(runtime)` 拿到可测的 Hono app\n- 覆盖：路由、各 builder、各 parser（含 YAML 订阅）、country grouping、selectedRules 向后兼容\n\n## 关键约定\n\n- `.jsx` 文件用 Hono JSX runtime，**不是 React**\n- Base64 输入用 `tryDecodeSubscriptionLines()` 处理（同时支持原文和 Base64）\n- 错误用 `ServiceError` 子类（`InvalidPayloadError`、`MissingDependencyError`），返回干净响应\n- i18n：zh-CN / en-US / fa-IR，文件在 `src/i18n/`\n\n## 本地工作流\n\n- 本地分层规划放 `.roadmap/roadmap.md`（已 `.gitignore`）；更新前先同步 GitHub open issues\n- 个人偏好、沙盒、临时上下文写入 `AGENTS.local.md`（不提交）\n- Claude 共享规则放 `CLAUDE.md`，个人覆盖放 `CLAUDE.local.md`\n\n## 文档参考\n\n代理工具配置问题查官方文档：\n- sing-box: https://sing-box.sagernet.org/\n- clash/mihomo: https://wiki.metacubex.one/\n- surge: https://blankwonder.gitbooks.io/surge-manual/content/\n- xray: https://xtls.github.io/config/\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/7Sageer/sublink-worker/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AGENTS.md\n\n## 协作偏好\n\n- 用中文回复；代码注释用英文，注释写 why 不写 how。\n- 简洁直接，不要多余总结和解释；除非存在高风险或信息缺口，直接写代码。\n- 函数式优先，TS/JS 中避免 OOP；新功能优先复用或重构现有代码。\n- 遵循 KISS、DRY 原则；从第一性原理解构问题，警惕 XY 问题。\n- 发现不合理的需求或方向要立即指出，不奉承。\n\n## 项目概览\n\nSublink Worker 是多平台代理订阅转换器：将各类协议（ShadowSocks/VMess/VLESS/Hysteria2/Trojan/TUIC）转为客户端配置（Sing-Box/Clash/Xray/Surge）。同一份代码跑在 Cloudflare Workers / Node.js / Vercel / Docker 上。技术栈：Hono（Web/JSX SSR）+ Vitest + Wrangler + esbuild + ioredis。\n\n## 常用命令\n\n- `npm run dev` — Wrangler 本地开发（Cloudflare Workers 入口）\n- `npm run dev:node` — esbuild bundle + 启动 Node.js server\n- `npm test` — Vitest（基于 `@cloudflare/vitest-pool-workers`，依赖 `wrangler.toml`）\n- `npx vitest test/<file>.test.js` — 跑单个测试文件\n- `npm run build` — Vercel 构建（输出到 `dist/vercel/`）\n- `npm run deploy` — `setup-kv` + `wrangler deploy`\n\n无 ESLint/Prettier/Biome 配置，未启用自动格式化。\n\n## 多运行时架构\n\n入口分平台：`src/worker.jsx`（Cloudflare）、`src/platforms/node-server.js`（Node/Docker）、`api/index.js`（Vercel）。三者都通过 `createApp(runtime)`（`src/app/createApp.jsx`）创建同一个 Hono app。\n\n- `src/runtime/{cloudflare,node,vercel}.js` 提供平台适配\n- `src/runtime/runtimeConfig.js` 规范化 KV、资源获取、日志、环境变量默认值\n\n新增运行时：在 `src/runtime/` 加 adapter，按需在 `src/adapters/kv/` 加 KV 实现，按需在 `src/platforms/` 加入口。\n\n## KV 存储抽象\n\n统一接口：`get(key)`、`put(key, value, options)`、`delete(key)`。实现：`CloudflareKVAdapter`、`RedisKVAdapter`（ioredis）、`UpstashKVAdapter`（REST）、`MemoryKVAdapter`。\n\n- 服务层：`ShortLinkService`（短链）、`ConfigStorageService`（base config 存储，默认 30 天 TTL）\n- Node/Vercel 优先级：Redis > Upstash/Vercel KV > 内存兜底；`DISABLE_MEMORY_KV=true` 关闭兜底\n- Cloudflare 用 `wrangler.toml` 的 `SUBLINK_KV` 与 `ASSETS` binding\n\n环境变量：`REDIS_URL` / `REDIS_HOST`+`REDIS_PORT` / `REDIS_USERNAME` / `REDIS_PASSWORD` / `REDIS_TLS` / `REDIS_KEY_PREFIX`、`KV_REST_API_URL`+`KV_REST_API_TOKEN`、`CONFIG_TTL_SECONDS`、`SHORT_LINK_TTL_SECONDS`、`STATIC_DIR`、`PORT`。\n\n## 协议解析与配置构建\n\n**ProxyParser**（`src/parsers/ProxyParser.js`）按 URL scheme 分发到 `src/parsers/protocols/<protocol>Parser.js`。HTTP(S) 订阅走 `httpSubscriptionFetcher` → `subscriptionContentParser`，自动识别 Sing-Box JSON / Clash YAML / Surge INI / Base64 列表。\n\n返回值约定：\n- 协议 parser：`{ tag, type, ...protocolFields }`\n- 订阅级 parser：`{ type: 'yamlConfig'|'singboxConfig'|'surgeConfig', config, proxies }`\n\n**新增协议**：在 `src/parsers/protocols/` 加 parser，并在 `ProxyParser.js` 的 `protocolParsers` map 注册。\n\n**Builder 模式**：`SingboxConfigBuilder` / `ClashConfigBuilder` / `SurgeConfigBuilder` 都继承 `BaseConfigBuilder`。子类必须实现：`getProxies()`、`getProxyName(proxy)`、`convertProxy(proxy)`、`addProxyToConfig(proxy)`、`addAutoSelectGroup(list)`、`addNodeSelectGroup(list)`、`addOutboundGroups(outbounds, list)`、`addCustomRuleGroups(list)`、`addFallBackGroup(list)`、`addCountryGroups()`、`formatConfig()`。\n\n**Config Override**：订阅含完整配置时，`applyConfigOverrides()` 合并非代理字段到 base config；blacklist（proxies、rules、rule-providers）永远不被覆盖；Clash `proxy-groups` 可被订阅覆盖以保留用户分组结构。\n\n国家分组逻辑在 `src/utils.js#groupProxiesByCountry`。\n\n## 测试\n\nVitest + `@cloudflare/vitest-pool-workers`，配置 `vitest.config.js` 指向 `wrangler.toml`。测试文件在 `test/`。\n\n- 写测试时用 `MemoryKVAdapter` 做 KV，用 `createApp(runtime)` 拿到可测的 Hono app\n- 覆盖：路由、各 builder、各 parser（含 YAML 订阅）、country grouping、selectedRules 向后兼容\n\n## 关键约定\n\n- `.jsx` 文件用 Hono JSX runtime，**不是 React**\n- Base64 输入用 `tryDecodeSubscriptionLines()` 处理（同时支持原文和 Base64）\n- 错误用 `ServiceError` 子类（`InvalidPayloadError`、`MissingDependencyError`），返回干净响应\n- i18n：zh-CN / en-US / fa-IR，文件在 `src/i18n/`\n\n## 本地工作流\n\n- 本地分层规划放 `.roadmap/roadmap.md`（已 `.gitignore`）；更新前先同步 GitHub open issues\n- 个人偏好、沙盒、临时上下文写入 `AGENTS.local.md`（不提交）\n- Claude 共享规则放 `CLAUDE.md`，个人覆盖放 `CLAUDE.local.md`\n\n## 文档参考\n\n代理工具配置问题查官方文档：\n- sing-box: https://sing-box.sagernet.org/\n- clash/mihomo: https://wiki.metacubex.one/\n- surge: https://blankwonder.gitbooks.io/surge-manual/content/\n- xray: https://xtls.github.io/config/\n","isInternal":false,"tokens":1682,"sizeBytes":5118},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/7Sageer/sublink-worker/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## 协作偏好\n\n- 用中文回复；代码注释用英文，注释写 why 不写 how。\n- 简洁直接，不要多余总结和解释；除非存在高风险或信息缺口，直接写代码。\n- 函数式优先，TS/JS 中避免 OOP；新功能优先复用或重构现有代码。\n- 遵循 KISS、DRY 和 `ai-coding-discipline` 规则。\n- 从第一性原理解构问题，警惕 XY 问题；发现不合理方向立即指出，不奉承。\n- 架构权衡参考 `ddia-principles` 和 `software-design-philosophy`。\n\n## 项目概览\n\nSublink Worker 是多平台代理订阅转换器：将各类协议（ShadowSocks/VMess/VLESS/Hysteria2/Trojan/TUIC）转为客户端配置（Sing-Box/Clash/Xray/Surge）。同一份代码跑在 Cloudflare Workers / Node.js / Vercel / Docker 上。技术栈：Hono（Web/JSX SSR）+ Vitest + Wrangler + esbuild + ioredis。\n\n## 常用命令\n\n- `npm run dev` — Wrangler 本地开发（Cloudflare Workers 入口）\n- `npm run dev:node` — esbuild bundle + 启动 Node.js server（Docker 同此入口）\n- `npm test` — Vitest（基于 `@cloudflare/vitest-pool-workers`，依赖 `wrangler.toml`）\n- `npx vitest test/<file>.test.js` — 跑单个测试文件\n- `npm run build` — Vercel 构建（输出到 `dist/vercel/`）\n- `npm run deploy` — `setup-kv` + `wrangler deploy`\n\n无 ESLint/Prettier/Biome 配置，未启用自动格式化。\n\n## 多运行时架构\n\n入口分平台：`src/worker.jsx`（Cloudflare）、`src/platforms/node-server.js`（Node/Docker）、`api/index.js`（Vercel）。三者都通过 `createApp(runtime)`（`src/app/createApp.jsx`）创建同一个 Hono app。\n\n- `src/runtime/{cloudflare,node,vercel}.js` 提供平台适配\n- `src/runtime/runtimeConfig.js` 规范化 KV、资源获取、日志、环境变量默认值\n\n新增运行时：在 `src/runtime/` 加 adapter，按需在 `src/adapters/kv/` 加 KV 实现，按需在 `src/platforms/` 加入口。\n\n## KV 存储抽象\n\n统一接口：`get(key)`、`put(key, value, options)`、`delete(key)`。实现：`CloudflareKVAdapter`、`RedisKVAdapter`（ioredis）、`UpstashKVAdapter`（REST）、`MemoryKVAdapter`。\n\n- 服务层：`ShortLinkService`（短链）、`ConfigStorageService`（base config 存储，默认 30 天 TTL）\n- Node/Vercel 优先级：Redis > Upstash/Vercel KV > 内存兜底；`DISABLE_MEMORY_KV=true` 关闭兜底\n- Cloudflare 用 `wrangler.toml` 的 `SUBLINK_KV` 与 `ASSETS` binding\n\n环境变量：`REDIS_URL` / `REDIS_HOST`+`REDIS_PORT` / `REDIS_USERNAME` / `REDIS_PASSWORD` / `REDIS_TLS` / `REDIS_KEY_PREFIX`、`KV_REST_API_URL`+`KV_REST_API_TOKEN`、`CONFIG_TTL_SECONDS`、`SHORT_LINK_TTL_SECONDS`、`STATIC_DIR`、`PORT`。\n\n## 协议解析与配置构建\n\n**ProxyParser**（`src/parsers/ProxyParser.js`）按 URL scheme 分发到 `src/parsers/protocols/<protocol>Parser.js`。HTTP(S) 订阅走 `httpSubscriptionFetcher` → `subscriptionContentParser`，自动识别 Sing-Box JSON / Clash YAML / Surge INI / Base64 列表。\n\n返回值约定：\n- 协议 parser：`{ tag, type, ...protocolFields }`\n- 订阅级 parser：`{ type: 'yamlConfig'|'singboxConfig'|'surgeConfig', config, proxies }`\n\n**新增协议**：在 `src/parsers/protocols/` 加 parser，并在 `ProxyParser.js` 的 `protocolParsers` map 注册。\n\n**Builder 模式**：`SingboxConfigBuilder` / `ClashConfigBuilder` / `SurgeConfigBuilder` 都继承 `BaseConfigBuilder`。子类必须实现：`getProxies()`、`getProxyName(proxy)`、`convertProxy(proxy)`、`addProxyToConfig(proxy)`、`addAutoSelectGroup(list)`、`addNodeSelectGroup(list)`、`addOutboundGroups(outbounds, list)`、`addCustomRuleGroups(list)`、`addFallBackGroup(list)`、`addCountryGroups()`、`formatConfig()`。\n\n**Config Override**：订阅含完整配置时，`applyConfigOverrides()` 合并非代理字段到 base config；blacklist（proxies、rules、rule-providers）永远不被覆盖；Clash `proxy-groups` 可被订阅覆盖以保留用户分组结构。\n\n国家分组逻辑在 `src/utils.js#groupProxiesByCountry`。\n\n## 测试\n\nVitest + `@cloudflare/vitest-pool-workers`，配置 `vitest.config.js` 指向 `wrangler.toml`。测试文件在 `test/`。\n\n- 写测试时用 `MemoryKVAdapter` 做 KV，用 `createApp(runtime)` 拿到可测的 Hono app\n- 覆盖：路由、各 builder、各 parser（含 YAML 订阅）、country grouping、selectedRules 向后兼容\n\n## 关键约定\n\n- `.jsx` 文件用 Hono JSX runtime，**不是 React**\n- Base64 输入用 `tryDecodeSubscriptionLines()` 处理（同时支持原文和 Base64）\n- 错误用 `ServiceError` 子类（`InvalidPayloadError`、`MissingDependencyError`），返回干净响应\n- i18n：zh-CN / en-US / fa-IR，文件在 `src/i18n/`\n\n## 本地工作流\n\n- 本地分层规划放 `.roadmap/roadmap.md`（已 `.gitignore`）；更新前先同步 GitHub open issues，每条记录留 issue 链接、优先级依据、下一步\n- 个人偏好、沙盒、临时上下文写入 `CLAUDE.local.md`（不提交）\n- 通用 agent 规则放 `AGENTS.md` / `AGENTS.local.md`\n- Claude 本地设置写入 `.claude/settings.local.json`（不提交）\n\n## 文档参考\n\n代理工具配置问题查官方文档：\n- sing-box: https://sing-box.sagernet.org/\n- clash/mihomo: https://wiki.metacubex.one/\n- surge: https://blankwonder.gitbooks.io/surge-manual/content/\n- xray: https://xtls.github.io/config/\n","isInternal":false,"tokens":1775,"sizeBytes":5452}],"systemPromptSnippet":"<yakaai_skills repo=\"7Sageer/sublink-worker\">\n<!-- File: AGENTS.md (Tokens: ~1682 | Category: root-instruction) -->\n# AGENTS.md\n\n## 协作偏好\n\n- 用中文回复；代码注释用英文，注释写 why 不写 how。\n- 简洁直接，不要多余总结和解释；除非存在高风险或信息缺口，直接写代码。\n- 函数式优先，TS/JS 中避免 OOP；新功能优先复用或重构现有代码。\n- 遵循 KISS、DRY 原则；从第一性原理解构问题，警惕 XY 问题。\n- 发现不合理的需求或方向要立即指出，不奉承。\n\n## 项目概览\n\nSublink Worker 是多平台代理订阅转换器：将各类协议（ShadowSocks/VMess/VLESS/Hysteria2/Trojan/TUIC）转为客户端配置（Sing-Box/Clash/Xray/Surge）。同一份代码跑在 Cloudflare Workers / Node.js / Vercel / Docker 上。技术栈：Hono（Web/JSX SSR）+ Vitest + Wrangler + esbuild + ioredis。\n\n## 常用命令\n\n- `npm run dev` — Wrangler 本地开发（Cloudflare Workers 入口）\n- `npm run dev:node` — esbuild bundle + 启动 Node.js server\n- `npm test` — Vitest（基于 `@cloudflare/vitest-pool-workers`，依赖 `wrangler.toml`）\n- `npx vitest test/<file>.test.js` — 跑单个测试文件\n- `npm run build` — Vercel 构建（输出到 `dist/vercel/`）\n- `npm run deploy` — `setup-kv` + `wrangler deploy`\n\n无 ESLint/Prettier/Biome 配置，未启用自动格式化。\n\n## 多运行时架构\n\n入口分平台：`src/worker.jsx`（Cloudflare）、`src/platforms/node-server.js`（Node/Docker）、`api/index.js`（Vercel）。三者都通过 `createApp(runtime)`（`src/app/createApp.jsx`）创建同一个 Hono app。\n\n- `src/runtime/{cloudflare,node,vercel}.js` 提供平台适配\n- `src/runtime/runtimeConfig.js` 规范化 KV、资源获取、日志、环境变量默认值\n\n新增运行时：在 `src/runtime/` 加 adapter，按需在 `src/adapters/kv/` 加 KV 实现，按需在 `src/platforms/` 加入口。\n\n## KV 存储抽象\n\n统一接口：`get(key)`、`put(key, value, options)`、`delete(key)`。实现：`CloudflareKVAdapter`、`RedisKVAdapter`（ioredis）、`UpstashKVAdapter`（REST）、`MemoryKVAdapter`。\n\n- 服务层：`ShortLinkService`（短链）、`ConfigStorageService`（base config 存储，默认 30 天 TTL）\n- Node/Vercel 优先级：Redis > Upstash/Vercel KV > 内存兜底；`DISABLE_MEMORY_KV=true` 关闭兜底\n- Cloudflare 用 `wrangler.toml` 的 `SUBLINK_KV` 与 `ASSETS` binding\n\n环境变量：`REDIS_URL` / `REDIS_HOST`+`REDIS_PORT` / `REDIS_USERNAME` / `REDIS_PASSWORD` / `REDIS_TLS` / `REDIS_KEY_PREFIX`、`KV_REST_API_URL`+`KV_REST_API_TOKEN`、`CONFIG_TTL_SECONDS`、`SHORT_LINK_TTL_SECONDS`、`STATIC_DIR`、`PORT`。\n\n## 协议解析与配置构建\n\n**ProxyParser**（`src/parsers/ProxyParser.js`）按 URL scheme 分发到 `src/parsers/protocols/<protocol>Parser.js`。HTTP(S) 订阅走 `httpSubscriptionFetcher` → `subscriptionContentParser`，自动识别 Sing-Box JSON / Clash YAML / Surge INI / Base64 列表。\n\n返回值约定：\n- 协议 parser：`{ tag, type, ...protocolFields }`\n- 订阅级 parser：`{ type: 'yamlConfig'|'singboxConfig'|'surgeConfig', config, proxies }`\n\n**新增协议**：在 `src/parsers/protocols/` 加 parser，并在 `ProxyParser.js` 的 `protocolParsers` map 注册。\n\n**Builder 模式**：`SingboxConfigBuilder` / `ClashConfigBuilder` / `SurgeConfigBuilder` 都继承 `BaseConfigBuilder`。子类必须实现：`getProxies()`、`getProxyName(proxy)`、`convertProxy(proxy)`、`addProxyToConfig(proxy)`、`addAutoSelectGroup(list)`、`addNodeSelectGroup(list)`、`addOutboundGroups(outbounds, list)`、`addCustomRuleGroups(list)`、`addFallBackGroup(list)`、`addCountryGroups()`、`formatConfig()`。\n\n**Config Override**：订阅含完整配置时，`applyConfigOverrides()` 合并非代理字段到 base config；blacklist（proxies、rules、rule-providers）永远不被覆盖；Clash `proxy-groups` 可被订阅覆盖以保留用户分组结构。\n\n国家分组逻辑在 `src/utils.js#groupProxiesByCountry`。\n\n## 测试\n\nVitest + `@cloudflare/vitest-pool-workers`，配置 `vitest.config.js` 指向 `wrangler.toml`。测试文件在 `test/`。\n\n- 写测试时用 `MemoryKVAdapter` 做 KV，用 `createApp(runtime)` 拿到可测的 Hono app\n- 覆盖：路由、各 builder、各 parser（含 YAML 订阅）、country grouping、selectedRules 向后兼容\n\n## 关键约定\n\n- `.jsx` 文件用 Hono JSX runtime，**不是 React**\n- Base64 输入用 `tryDecodeSubscriptionLines()` 处理（同时支持原文和 Base64）\n- 错误用 `ServiceError` 子类（`InvalidPayloadError`、`MissingDependencyError`），返回干净响应\n- i18n：zh-CN / en-US / fa-IR，文件在 `src/i18n/`\n\n## 本地工作流\n\n- 本地分层规划放 `.roadmap/roadmap.md`（已 `.gitignore`）；更新前先同步 GitHub open issues\n- 个人偏好、沙盒、临时上下文写入 `AGENTS.local.md`（不提交）\n- Claude 共享规则放 `CLAUDE.md`，个人覆盖放 `CLAUDE.local.md`\n\n## 文档参考\n\n代理工具配置问题查官方文档：\n- sing-box: https://sing-box.sagernet.org/\n- clash/mihomo: https://wiki.metacubex.one/\n- surge: https://blankwonder.gitbooks.io/surge-manual/content/\n- xray: https://xtls.github.io/config/\n\n<!-- File: CLAUDE.md (Tokens: ~1775 | Category: claude-rule) -->\n# CLAUDE.md\n\nThis file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.\n\n## 协作偏好\n\n- 用中文回复；代码注释用英文，注释写 why 不写 how。\n- 简洁直接，不要多余总结和解释；除非存在高风险或信息缺口，直接写代码。\n- 函数式优先，TS/JS 中避免 OOP；新功能优先复用或重构现有代码。\n- 遵循 KISS、DRY 和 `ai-coding-discipline` 规则。\n- 从第一性原理解构问题，警惕 XY 问题；发现不合理方向立即指出，不奉承。\n- 架构权衡参考 `ddia-principles` 和 `software-design-philosophy`。\n\n## 项目概览\n\nSublink Worker 是多平台代理订阅转换器：将各类协议（ShadowSocks/VMess/VLESS/Hysteria2/Trojan/TUIC）转为客户端配置（Sing-Box/Clash/Xray/Surge）。同一份代码跑在 Cloudflare Workers / Node.js / Vercel / Docker 上。技术栈：Hono（Web/JSX SSR）+ Vitest + Wrangler + esbuild + ioredis。\n\n## 常用命令\n\n- `npm run dev` — Wrangler 本地开发（Cloudflare Workers 入口）\n- `npm run dev:node` — esbuild bundle + 启动 Node.js server（Docker 同此入口）\n- `npm test` — Vitest（基于 `@cloudflare/vitest-pool-workers`，依赖 `wrangler.toml`）\n- `npx vitest test/<file>.test.js` — 跑单个测试文件\n- `npm run build` — Vercel 构建（输出到 `dist/vercel/`）\n- `npm run deploy` — `setup-kv` + `wrangler deploy`\n\n无 ESLint/Prettier/Biome 配置，未启用自动格式化。\n\n## 多运行时架构\n\n入口分平台：`src/worker.jsx`（Cloudflare）、`src/platforms/node-server.js`（Node/Docker）、`api/index.js`（Vercel）。三者都通过 `createApp(runtime)`（`src/app/createApp.jsx`）创建同一个 Hono app。\n\n- `src/runtime/{cloudflare,node,vercel}.js` 提供平台适配\n- `src/runtime/runtimeConfig.js` 规范化 KV、资源获取、日志、环境变量默认值\n\n新增运行时：在 `src/runtime/` 加 adapter，按需在 `src/adapters/kv/` 加 KV 实现，按需在 `src/platforms/` 加入口。\n\n## KV 存储抽象\n\n统一接口：`get(key)`、`put(key, value, options)`、`delete(key)`。实现：`CloudflareKVAdapter`、`RedisKVAdapter`（ioredis）、`UpstashKVAdapter`（REST）、`MemoryKVAdapter`。\n\n- 服务层：`ShortLinkService`（短链）、`ConfigStorageService`（base config 存储，默认 30 天 TTL）\n- Node/Vercel 优先级：Redis > Upstash/Vercel KV > 内存兜底；`DISABLE_MEMORY_KV=true` 关闭兜底\n- Cloudflare 用 `wrangler.toml` 的 `SUBLINK_KV` 与 `ASSETS` binding\n\n环境变量：`REDIS_URL` / `REDIS_HOST`+`REDIS_PORT` / `REDIS_USERNAME` / `REDIS_PASSWORD` / `REDIS_TLS` / `REDIS_KEY_PREFIX`、`KV_REST_API_URL`+`KV_REST_API_TOKEN`、`CONFIG_TTL_SECONDS`、`SHORT_LINK_TTL_SECONDS`、`STATIC_DIR`、`PORT`。\n\n## 协议解析与配置构建\n\n**ProxyParser**（`src/parsers/ProxyParser.js`）按 URL scheme 分发到 `src/parsers/protocols/<protocol>Parser.js`。HTTP(S) 订阅走 `httpSubscriptionFetcher` → `subscriptionContentParser`，自动识别 Sing-Box JSON / Clash YAML / Surge INI / Base64 列表。\n\n返回值约定：\n- 协议 parser：`{ tag, type, ...protocolFields }`\n- 订阅级 parser：`{ type: 'yamlConfig'|'singboxConfig'|'surgeConfig', config, proxies }`\n\n**新增协议**：在 `src/parsers/protocols/` 加 parser，并在 `ProxyParser.js` 的 `protocolParsers` map 注册。\n\n**Builder 模式**：`SingboxConfigBuilder` / `ClashConfigBuilder` / `SurgeConfigBuilder` 都继承 `BaseConfigBuilder`。子类必须实现：`getProxies()`、`getProxyName(proxy)`、`convertProxy(proxy)`、`addProxyToConfig(proxy)`、`addAutoSelectGroup(list)`、`addNodeSelectGroup(list)`、`addOutboundGroups(outbounds, list)`、`addCustomRuleGroups(list)`、`addFallBackGroup(list)`、`addCountryGroups()`、`formatConfig()`。\n\n**Config Override**：订阅含完整配置时，`applyConfigOverrides()` 合并非代理字段到 base config；blacklist（proxies、rules、rule-providers）永远不被覆盖；Clash `proxy-groups` 可被订阅覆盖以保留用户分组结构。\n\n国家分组逻辑在 `src/utils.js#groupProxiesByCountry`。\n\n## 测试\n\nVitest + `@cloudflare/vitest-pool-workers`，配置 `vitest.config.js` 指向 `wrangler.toml`。测试文件在 `test/`。\n\n- 写测试时用 `MemoryKVAdapter` 做 KV，用 `createApp(runtime)` 拿到可测的 Hono app\n- 覆盖：路由、各 builder、各 parser（含 YAML 订阅）、country grouping、selectedRules 向后兼容\n\n## 关键约定\n\n- `.jsx` 文件用 Hono JSX runtime，**不是 React**\n- Base64 输入用 `tryDecodeSubscriptionLines()` 处理（同时支持原文和 Base64）\n- 错误用 `ServiceError` 子类（`InvalidPayloadError`、`MissingDependencyError`），返回干净响应\n- i18n：zh-CN / en-US / fa-IR，文件在 `src/i18n/`\n\n## 本地工作流\n\n- 本地分层规划放 `.roadmap/roadmap.md`（已 `.gitignore`）；更新前先同步 GitHub open issues，每条记录留 issue 链接、优先级依据、下一步\n- 个人偏好、沙盒、临时上下文写入 `CLAUDE.local.md`（不提交）\n- 通用 agent 规则放 `AGENTS.md` / `AGENTS.local.md`\n- Claude 本地设置写入 `.claude/settings.local.json`（不提交）\n\n## 文档参考\n\n代理工具配置问题查官方文档：\n- sing-box: https://sing-box.sagernet.org/\n- clash/mihomo: https://wiki.metacubex.one/\n- surge: https://blankwonder.gitbooks.io/surge-manual/content/\n- xray: https://xtls.github.io/config/\n</yakaai_skills>"}