mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 14:25:51 +00:00
* feat: 接入 weixin 服务层与命令入口 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * feat: 注册内建 weixin channel 插件 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix: 修正 channel permission relay 路由与能力判定 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix: 修复 builtin channel 的 ChannelsNotice 误报 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * docs: 补充内建 weixin channel 使用说明 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * docs: 更新微信 channel 接入计划状态 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix: 延迟加载 weixin 登录二维码依赖 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix: 改用 qrcode 生成 weixin 登录二维码 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix: 修正 vite 构建的 Windows 路径解析 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * chore: 删除临时规划文档 wx_channel.md 并还原 package.json 排序 wx_channel.md 内容已整合到 docs/features/channels.md,不再需要。 package.json 中 @ant/model-provider 位置从原始位置被无意移动,还原。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: 将 weixin 模块从 src/ 迁移至 packages/weixin 工作区包 将 src/services/weixin/ 中的纯业务逻辑迁入 @claude-code-best/weixin workspace 包,降低 src/ 耦合度。仅保留 server.ts 作为薄适配层。 - 迁移 7 个无修改的纯模块 (types/api/accounts/login/pairing/media/send) - monitor.ts 内联 PERMISSION_REPLY_RE 正则,解除对 src/ 的依赖 - permissions.ts 本地定义 ChannelPermissionRequestParams 接口 - cli.ts 拆分:serve 子命令通过回调注入,login/access 保留在包内 - server.ts 重写为从 @claude-code-best/weixin 导入 - 新增 cli-serve.ts 作为 serve 入口薄壳 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修正 weixin barrel export 中 interface 的导出方式 ChannelPermissionRequestParams 是纯类型,必须用 export type 导出, 否则 Bun 运行时会报 "export not found" 错误。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: 将 server.ts 迁入 packages/weixin,彻底移除 src/services/weixin/ 通过依赖注入(WeixinServerDeps)解耦 src/ 依赖(analytics、config、 MCP channel schema),server.ts 完全移入包内。cli.tsx 入口处一次性 注入所有依赖。 src/services/weixin/ 目录已完全删除。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: 修复 markdownToPlainText 中代码块正则的 ReDoS 风险 用非正则的线性扫描替代 \`\`\`[\s\S]*?\n([\s\S]*?)\`\`\` 匹配, 避免在含有大量重复 \`\`\` 序列的输入上触发多项式回溯。 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: 1111 <11111@asd.c> Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
79 lines
2.8 KiB
TypeScript
79 lines
2.8 KiB
TypeScript
/**
|
|
* Approved channel plugins allowlist. --channels plugin:name@marketplace
|
|
* entries only register if {marketplace, plugin} is on this list. server:
|
|
* entries always fail (schema is plugin-only). The
|
|
* --dangerously-load-development-channels flag bypasses for both kinds.
|
|
* Lives in GrowthBook so it can be updated without a release.
|
|
*
|
|
* Plugin-level granularity: if a plugin is approved, all its channel
|
|
* servers are. Per-server gating was overengineering — a plugin that
|
|
* sprouts a malicious second server is already compromised, and per-server
|
|
* entries would break on harmless plugin refactors.
|
|
*
|
|
* The allowlist check is a pure {marketplace, plugin} comparison against
|
|
* the user's typed tag. The gate's separate 'marketplace' step verifies
|
|
* the tag matches what's actually installed before this check runs.
|
|
*/
|
|
|
|
import { z } from 'zod/v4'
|
|
import { BUILTIN_MARKETPLACE_NAME } from '../../plugins/builtinPlugins.js'
|
|
import { lazySchema } from '../../utils/lazySchema.js'
|
|
import { parsePluginIdentifier } from '../../utils/plugins/pluginIdentifier.js'
|
|
import { getFeatureValue_CACHED_MAY_BE_STALE } from '../analytics/growthbook.js'
|
|
|
|
export type ChannelAllowlistEntry = {
|
|
marketplace: string
|
|
plugin: string
|
|
}
|
|
|
|
const ChannelAllowlistSchema = lazySchema(() =>
|
|
z.array(
|
|
z.object({
|
|
marketplace: z.string(),
|
|
plugin: z.string(),
|
|
}),
|
|
),
|
|
)
|
|
|
|
export function getChannelAllowlist(): ChannelAllowlistEntry[] {
|
|
const raw = getFeatureValue_CACHED_MAY_BE_STALE<unknown>(
|
|
'tengu_harbor_ledger',
|
|
[],
|
|
)
|
|
const parsed = ChannelAllowlistSchema().safeParse(raw)
|
|
return parsed.success ? parsed.data : []
|
|
}
|
|
|
|
/**
|
|
* Overall channels on/off. Always enabled — GrowthBook gate bypassed.
|
|
*/
|
|
export function isChannelsEnabled(): boolean {
|
|
return true
|
|
}
|
|
|
|
/**
|
|
* Pure allowlist check keyed off the connection's pluginSource — for UI
|
|
* pre-filtering so the IDE only shows "Enable channel?" for servers that will
|
|
* actually pass the gate. Not a security boundary: channel_enable still runs
|
|
* the full gate. Matches the allowlist comparison inside gateChannelServer()
|
|
* but standalone (no session/marketplace coupling — those are tautologies
|
|
* when the entry is derived from pluginSource).
|
|
*
|
|
* Returns false for undefined pluginSource (non-plugin server — can never
|
|
* match the {marketplace, plugin}-keyed ledger) and for @-less sources
|
|
* (builtin/inline — same reason).
|
|
*/
|
|
export function isChannelAllowlisted(
|
|
pluginSource: string | undefined,
|
|
): boolean {
|
|
if (!pluginSource) return false
|
|
const { name, marketplace } = parsePluginIdentifier(pluginSource)
|
|
if (!marketplace) return false
|
|
if (marketplace === BUILTIN_MARKETPLACE_NAME && name === 'weixin') {
|
|
return true
|
|
}
|
|
return getChannelAllowlist().some(
|
|
e => e.plugin === name && e.marketplace === marketplace,
|
|
)
|
|
}
|