File size: 6,080 Bytes
6d60378
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python3
"""WorkBuddy 活跃上报探针 / 解冻工具.



用途

  probe    只读:查某账号 growth 任务状态 + streak

  report   写:向 /v2/report 发一条 chat_request_send(点亮活跃/连登 + 解锁 first_buddy)

  unlock   写:report -> agreement -> buddy/first(无猫号领免费猫)



用法

  python3 probe_active.py probe  00e26541

  python3 probe_active.py report 0225284f

  python3 probe_active.py unlock 0225284f --yes

  python3 probe_active.py report ALL --yes --gap 1.05   # 全池



注意

  - 默认 dry-run:写动作必须显式加 --yes

  - 单账号同接口间隔 >=1.05s(--gap)

  - body 必须含 userId 字段,否则服务端 200 但静默丢弃

"""
import json, os, sys, time, glob, argparse, urllib.request, urllib.error

AUTHS = "/root/workbuddy2api/auths"
CHAT_BASE = "https://copilot.tencent.com"   # growth / report
BILL_BASE = "https://www.codebuddy.cn"      # billing / report

def cred(prefix):
    hits = glob.glob(os.path.join(AUTHS, f"workbuddy-{prefix}*.json"))
    if not hits:
        raise SystemExit(f"no auth for {prefix}")
    d = json.load(open(hits[0]))
    a, acc = d["auth"], d["account"]
    return {"token": a["accessToken"], "domain": a.get("domain") or "",
            "uid": acc["uid"], "nick": acc.get("nickname", ""),
            "file": os.path.basename(hits[0])}

def call(c, method, path, body=None, host=CHAT_BASE, timeout=30):
    url = path if path.startswith("http") else host + path
    hdr = {"Authorization": "Bearer " + c["token"], "X-User-Id": c["uid"],
           "X-Domain": c["domain"], "Accept": "application/json",
           "Content-Type": "application/json",
           "User-Agent": "CLI/2.63.2 CodeBuddy/2.63.2",
           "Origin": "https://www.codebuddy.cn", "Referer": "https://www.codebuddy.cn/"}
    data = json.dumps(body).encode() if body is not None else None
    req = urllib.request.Request(url, data=data, headers=hdr, method=method)
    try:
        with urllib.request.urlopen(req, timeout=timeout) as r:
            return r.status, json.loads(r.read().decode("utf-8", "replace"))
    except urllib.error.HTTPError as e:
        t = e.read().decode("utf-8", "replace")
        try:    return e.code, json.loads(t)
        except Exception: return e.code, {"raw": t[:300]}
    except Exception as e:
        return -1, {"err": repr(e)}

def chat_event(c, conversation_id=None):
    """客户端 chat_request_send 事件形状(照抄 CLI,勿删 userId)。"""
    now = int(time.time() * 1000)
    cid = conversation_id or f"wb-active-{now}"
    return {"eventCode": "chat_request_send", "timestamp": now, "reportDelay": 0,
            "mode": "craft", "conversationId": cid, "requestId": cid,
            "inputLength": 12, "requestModelId": "deepseek-v4-flash",
            "requestModelName": "DeepSeek V4 Flash", "isPlan": False,
            "isAutoExecuteTerminal": False, "isAutoModify": False,
            "codebaseEnable": False, "maxToken": 0, "maxSteps": 0, "temperature": 0,
            "maxRetries": 0, "mentionContexts": [], "knowledgeId": [],
            "knowledgeName": [], "codebaseId": "", "mentionContextCount": 0,
            "command": "", "expertId": "", "recommendId": "", "skillId": "",
            "skillCount": 0, "totalCount": 0, "fileUri": "", "presentAt": now,
            "traceId": "", "rootRequestId": cid, "parentConversationId": cid,
            "agentName": "default", "agentType": "conversation", "userId": c["uid"]}

def report_activity(c):
    """点亮活跃/连登。返回 (status, code)."""
    st, r = call(c, "POST", "/v2/report", [chat_event(c)], host=BILL_BASE)
    return st, r.get("code")

def tasks(c):
    st, d = call(c, "GET", "/v2/activity/growth/tasks")
    out = {}
    for t in (d.get("data", {}).get("tasks") or []):
        out[t["task_code"]] = (t["accept_status"], t.get("progress"))
    return out

def unlock(c, n_reports=6):
    """无猫号解冻:report -> agreement -> buddy/first -> chat_5"""
    st, code = report_activity(c)
    print(f"  report      -> {st} code={code}")
    time.sleep(2)
    st, ag = call(c, "POST", "/activity/growth/buddy/agreement", {"agree": True})
    print(f"  agreement   -> {st} code={ag.get('code')}")
    st, bf = call(c, "POST", "/activity/growth/buddy/first", {})
    d = bf.get("data") or {}
    print(f"  buddy/first -> {st} {bf.get('msg')} credit={d.get('credit')} energy={d.get('energy')}")
    return bf

def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("action", choices=["probe", "report", "unlock"])
    ap.add_argument("account", help="uid 前缀,或 ALL")
    ap.add_argument("--yes", action="store_true", help="确认执行写操作")
    ap.add_argument("--gap", type=float, default=1.05)
    a = ap.parse_args()

    if a.account.upper() == "ALL":
        prefixes = [os.path.basename(p)[10:18]
                    for p in sorted(glob.glob(AUTHS + "/workbuddy-*.json"))]
    else:
        prefixes = [a.account]

    for pre in prefixes:
        c = cred(pre)
        print(f"== {c['uid'][:8]} ({c['nick']}) ==")
        if a.action == "probe":
            t = tasks(c)
            st, s = call(c, "GET", "/activity/growth/streak")
            print("  first_buddy:", t.get("first_buddy"),
                  "| RichMeow_Chat:", t.get("RichMeow_Chat"),
                  "| chat_5:", t.get("chat_5"))
            print("  streak.days:", (s.get("data", {}).get("streak", {}) or {}).get("days"))
        elif a.action == "report":
            if not a.yes:
                print("  [dry-run] 将上报 1 条 chat_request_send(加 --yes 执行)")
            else:
                print("  report ->", report_activity(c))
        else:  # unlock
            if not a.yes:
                print("  [dry-run] 将 report + agreement + buddy/first(加 --yes 执行)")
            else:
                unlock(c)
        time.sleep(a.gap)

if __name__ == "__main__":
    main()