Merge pull request #697 from xiaket/doc-remove-chinese-comments

[doc]translate Chinese comments
This commit is contained in:
Meng Zhuo 2026-02-24 08:36:18 +08:00 committed by GitHub
commit 7cbfa89a96
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 36 additions and 36 deletions

View file

@ -131,7 +131,7 @@ func main() {
workspace := cfg.WorkspacePath() workspace := cfg.WorkspacePath()
installer := skills.NewSkillInstaller(workspace) installer := skills.NewSkillInstaller(workspace)
// 获取全局配置目录和内置 skills 目录 // get global config directory and builtin skills directory
globalDir := filepath.Dir(getConfigPath()) globalDir := filepath.Dir(getConfigPath())
globalSkillsDir := filepath.Join(globalDir, "skills") globalSkillsDir := filepath.Join(globalDir, "skills")
builtinSkillsDir := filepath.Join(globalDir, "picoclaw", "skills") builtinSkillsDir := filepath.Join(globalDir, "picoclaw", "skills")

View file

@ -47,31 +47,31 @@ func (c *QQChannel) Start(ctx context.Context) error {
logger.InfoC("qq", "Starting QQ bot (WebSocket mode)") logger.InfoC("qq", "Starting QQ bot (WebSocket mode)")
// 创建 token source // create token source
credentials := &token.QQBotCredentials{ credentials := &token.QQBotCredentials{
AppID: c.config.AppID, AppID: c.config.AppID,
AppSecret: c.config.AppSecret, AppSecret: c.config.AppSecret,
} }
c.tokenSource = token.NewQQBotTokenSource(credentials) c.tokenSource = token.NewQQBotTokenSource(credentials)
// 创建子 context // create child context
c.ctx, c.cancel = context.WithCancel(ctx) c.ctx, c.cancel = context.WithCancel(ctx)
// 启动自动刷新 token 协程 // start auto-refresh token goroutine
if err := token.StartRefreshAccessToken(c.ctx, c.tokenSource); err != nil { if err := token.StartRefreshAccessToken(c.ctx, c.tokenSource); err != nil {
return fmt.Errorf("failed to start token refresh: %w", err) return fmt.Errorf("failed to start token refresh: %w", err)
} }
// 初始化 OpenAPI 客户端 // initialize OpenAPI client
c.api = botgo.NewOpenAPI(c.config.AppID, c.tokenSource).WithTimeout(5 * time.Second) c.api = botgo.NewOpenAPI(c.config.AppID, c.tokenSource).WithTimeout(5 * time.Second)
// 注册事件处理器 // register event handlers
intent := event.RegisterHandlers( intent := event.RegisterHandlers(
c.handleC2CMessage(), c.handleC2CMessage(),
c.handleGroupATMessage(), c.handleGroupATMessage(),
) )
// 获取 WebSocket 接入点 // get WebSocket endpoint
wsInfo, err := c.api.WS(c.ctx, nil, "") wsInfo, err := c.api.WS(c.ctx, nil, "")
if err != nil { if err != nil {
return fmt.Errorf("failed to get websocket info: %w", err) return fmt.Errorf("failed to get websocket info: %w", err)
@ -81,10 +81,10 @@ func (c *QQChannel) Start(ctx context.Context) error {
"shards": wsInfo.Shards, "shards": wsInfo.Shards,
}) })
// 创建并保存 sessionManager // create and save sessionManager
c.sessionManager = botgo.NewSessionManager() c.sessionManager = botgo.NewSessionManager()
// 在 goroutine 中启动 WebSocket 连接,避免阻塞 // start WebSocket connection in goroutine to avoid blocking
go func() { go func() {
if err := c.sessionManager.Start(wsInfo, c.tokenSource, &intent); err != nil { if err := c.sessionManager.Start(wsInfo, c.tokenSource, &intent); err != nil {
logger.ErrorCF("qq", "WebSocket session error", map[string]any{ logger.ErrorCF("qq", "WebSocket session error", map[string]any{
@ -116,12 +116,12 @@ func (c *QQChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
return fmt.Errorf("QQ bot not running") return fmt.Errorf("QQ bot not running")
} }
// 构造消息 // construct message
msgToCreate := &dto.MessageToCreate{ msgToCreate := &dto.MessageToCreate{
Content: msg.Content, Content: msg.Content,
} }
// C2C 消息发送 // send C2C message
_, err := c.api.PostC2CMessage(ctx, msg.ChatID, msgToCreate) _, err := c.api.PostC2CMessage(ctx, msg.ChatID, msgToCreate)
if err != nil { if err != nil {
logger.ErrorCF("qq", "Failed to send C2C message", map[string]any{ logger.ErrorCF("qq", "Failed to send C2C message", map[string]any{
@ -133,15 +133,15 @@ func (c *QQChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
return nil return nil
} }
// handleC2CMessage 处理 QQ 私聊消息 // handleC2CMessage handles QQ private messages
func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler { func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler {
return func(event *dto.WSPayload, data *dto.WSC2CMessageData) error { return func(event *dto.WSPayload, data *dto.WSC2CMessageData) error {
// 去重检查 // deduplication check
if c.isDuplicate(data.ID) { if c.isDuplicate(data.ID) {
return nil return nil
} }
// 提取用户信息 // extract user info
var senderID string var senderID string
if data.Author != nil && data.Author.ID != "" { if data.Author != nil && data.Author.ID != "" {
senderID = data.Author.ID senderID = data.Author.ID
@ -150,7 +150,7 @@ func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler {
return nil return nil
} }
// 提取消息内容 // extract message content
content := data.Content content := data.Content
if content == "" { if content == "" {
logger.DebugC("qq", "Received empty message, ignoring") logger.DebugC("qq", "Received empty message, ignoring")
@ -162,7 +162,7 @@ func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler {
"length": len(content), "length": len(content),
}) })
// 转发到消息总线 // forward to message bus
metadata := map[string]string{ metadata := map[string]string{
"message_id": data.ID, "message_id": data.ID,
"peer_kind": "direct", "peer_kind": "direct",
@ -175,15 +175,15 @@ func (c *QQChannel) handleC2CMessage() event.C2CMessageEventHandler {
} }
} }
// handleGroupATMessage 处理群@消息 // handleGroupATMessage handles group @messages
func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler { func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler {
return func(event *dto.WSPayload, data *dto.WSGroupATMessageData) error { return func(event *dto.WSPayload, data *dto.WSGroupATMessageData) error {
// 去重检查 // deduplication check
if c.isDuplicate(data.ID) { if c.isDuplicate(data.ID) {
return nil return nil
} }
// 提取用户信息 // extract user info
var senderID string var senderID string
if data.Author != nil && data.Author.ID != "" { if data.Author != nil && data.Author.ID != "" {
senderID = data.Author.ID senderID = data.Author.ID
@ -192,7 +192,7 @@ func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler {
return nil return nil
} }
// 提取消息内容(去掉 @ 机器人部分) // extract message content (remove @bot part)
content := data.Content content := data.Content
if content == "" { if content == "" {
logger.DebugC("qq", "Received empty group message, ignoring") logger.DebugC("qq", "Received empty group message, ignoring")
@ -205,7 +205,7 @@ func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler {
"length": len(content), "length": len(content),
}) })
// 转发到消息总线(使用 GroupID 作为 ChatID // forward to message bus (use GroupID as ChatID)
metadata := map[string]string{ metadata := map[string]string{
"message_id": data.ID, "message_id": data.ID,
"group_id": data.GroupID, "group_id": data.GroupID,
@ -219,7 +219,7 @@ func (c *QQChannel) handleGroupATMessage() event.GroupATMessageEventHandler {
} }
} }
// isDuplicate 检查消息是否重复 // isDuplicate checks if message is duplicate
func (c *QQChannel) isDuplicate(messageID string) bool { func (c *QQChannel) isDuplicate(messageID string) bool {
c.mu.Lock() c.mu.Lock()
defer c.mu.Unlock() defer c.mu.Unlock()
@ -230,9 +230,9 @@ func (c *QQChannel) isDuplicate(messageID string) bool {
c.processedIDs[messageID] = true c.processedIDs[messageID] = true
// 简单清理:限制 map 大小 // simple cleanup: limit map size
if len(c.processedIDs) > 10000 { if len(c.processedIDs) > 10000 {
// 清空一半 // clear half
count := 0 count := 0
for id := range c.processedIDs { for id := range c.processedIDs {
if count >= 5000 { if count >= 5000 {

View file

@ -200,7 +200,7 @@ func (c *SlackChannel) handleMessageEvent(ev *slackevents.MessageEvent) {
return return
} }
// 检查白名单,避免为被拒绝的用户下载附件 // check allowlist to avoid downloading attachments for rejected users
if !c.IsAllowed(ev.User) { if !c.IsAllowed(ev.User) {
logger.DebugCF("slack", "Message rejected by allowlist", map[string]any{ logger.DebugCF("slack", "Message rejected by allowlist", map[string]any{
"user_id": ev.User, "user_id": ev.User,
@ -232,9 +232,9 @@ func (c *SlackChannel) handleMessageEvent(ev *slackevents.MessageEvent) {
content = c.stripBotMention(content) content = c.stripBotMention(content)
var mediaPaths []string var mediaPaths []string
localFiles := []string{} // 跟踪需要清理的本地文件 localFiles := []string{} // track local files that need cleanup
// 确保临时文件在函数返回时被清理 // ensure temp files are cleaned up when function returns
defer func() { defer func() {
for _, file := range localFiles { for _, file := range localFiles {
if err := os.Remove(file); err != nil { if err := os.Remove(file); err != nil {

View file

@ -208,7 +208,7 @@ func (c *TelegramChannel) handleMessage(ctx context.Context, message *telego.Mes
senderID = fmt.Sprintf("%d|%s", user.ID, user.Username) senderID = fmt.Sprintf("%d|%s", user.ID, user.Username)
} }
// 检查白名单,避免为被拒绝的用户下载附件 // check allowlist to avoid downloading attachments for rejected users
if !c.IsAllowed(senderID) { if !c.IsAllowed(senderID) {
logger.DebugCF("telegram", "Message rejected by allowlist", map[string]any{ logger.DebugCF("telegram", "Message rejected by allowlist", map[string]any{
"user_id": senderID, "user_id": senderID,
@ -221,9 +221,9 @@ func (c *TelegramChannel) handleMessage(ctx context.Context, message *telego.Mes
content := "" content := ""
mediaPaths := []string{} mediaPaths := []string{}
localFiles := []string{} // 跟踪需要清理的本地文件 localFiles := []string{} // track local files that need cleanup
// 确保临时文件在函数返回时被清理 // ensure temp files are cleaned up when function returns
defer func() { defer func() {
for _, file := range localFiles { for _, file := range localFiles {
if err := os.Remove(file); err != nil { if err := os.Remove(file); err != nil {

View file

@ -55,9 +55,9 @@ func (info SkillInfo) validate() error {
type SkillsLoader struct { type SkillsLoader struct {
workspace string workspace string
workspaceSkills string // workspace skills (项目级别) workspaceSkills string // workspace skills (project-level)
globalSkills string // 全局 skills (~/.picoclaw/skills) globalSkills string // global skills (~/.picoclaw/skills)
builtinSkills string // 内置 skills builtinSkills string // builtin skills
} }
func NewSkillsLoader(workspace string, globalSkills string, builtinSkills string) *SkillsLoader { func NewSkillsLoader(workspace string, globalSkills string, builtinSkills string) *SkillsLoader {
@ -120,7 +120,7 @@ func (sl *SkillsLoader) ListSkills() []SkillInfo {
} }
func (sl *SkillsLoader) LoadSkill(name string) (string, bool) { func (sl *SkillsLoader) LoadSkill(name string) (string, bool) {
// 1. 优先从 workspace skills 加载(项目级别) // 1. load from workspace skills first (project-level)
if sl.workspaceSkills != "" { if sl.workspaceSkills != "" {
skillFile := filepath.Join(sl.workspaceSkills, name, "SKILL.md") skillFile := filepath.Join(sl.workspaceSkills, name, "SKILL.md")
if content, err := os.ReadFile(skillFile); err == nil { if content, err := os.ReadFile(skillFile); err == nil {
@ -128,7 +128,7 @@ func (sl *SkillsLoader) LoadSkill(name string) (string, bool) {
} }
} }
// 2. 其次从全局 skills 加载 (~/.picoclaw/skills) // 2. then load from global skills (~/.picoclaw/skills)
if sl.globalSkills != "" { if sl.globalSkills != "" {
skillFile := filepath.Join(sl.globalSkills, name, "SKILL.md") skillFile := filepath.Join(sl.globalSkills, name, "SKILL.md")
if content, err := os.ReadFile(skillFile); err == nil { if content, err := os.ReadFile(skillFile); err == nil {
@ -136,7 +136,7 @@ func (sl *SkillsLoader) LoadSkill(name string) (string, bool) {
} }
} }
// 3. 最后从内置 skills 加载 // 3. finally load from builtin skills
if sl.builtinSkills != "" { if sl.builtinSkills != "" {
skillFile := filepath.Join(sl.builtinSkills, name, "SKILL.md") skillFile := filepath.Join(sl.builtinSkills, name, "SKILL.md")
if content, err := os.ReadFile(skillFile); err == nil { if content, err := os.ReadFile(skillFile); err == nil {