File size: 13,073 Bytes
845178e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
#!/usr/bin/env python3
"""

WorkBuddy Token 提取工具(傻瓜版)



全自动检测和安装依赖,用户只需双击运行即可。



功能:

- 自动检测并安装 Python(如未安装)

- 自动安装脚本依赖

- 自动启动 WorkBuddy(调试模式)

- 自动提取 Token 并保存到桌面

"""

import os
import sys
import time
import json
import subprocess
import asyncio
import platform
from pathlib import Path


def run_cmd(cmd, check=True, shell=True):
    """执行命令并返回结果"""
    try:
        result = subprocess.run(
            cmd, shell=shell, capture_output=True, text=True, timeout=300
        )
        if check and result.returncode != 0:
            return False, result.stderr
        return True, result.stdout
    except subprocess.TimeoutExpired:
        return False, "命令执行超时"
    except Exception as e:
        return False, str(e)


def check_python():
    """检查 Python 是否安装"""
    py_names = ["python", "python3"] if platform.system() == "Windows" else ["python3", "python"]
    for name in py_names:
        try:
            result = subprocess.run(
                [name, "--version"], capture_output=True, text=True
            )
            if result.returncode == 0:
                version = result.stdout.strip()
                print(f"  ✅ Python 已安装: {version}")
                return True
        except FileNotFoundError:
            continue

    print("  ❌ Python 未安装,正在安装...")
    return False


def install_homebrew():
    """安装 Homebrew"""
    print("\n正在安装 Homebrew...")
    print("(这可能需要几分钟,请耐心等待)\n")

    cmd = '/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"'
    ok, msg = run_cmd(cmd, check=False)

    if ok:
        print("  ✅ Homebrew 安装成功!")
        return True
    else:
        print(f"  ⚠️ Homebrew 安装失败")
        print("\n请手动安装 Homebrew:")
        print("  打开终端,粘贴以下命令:")
        print("  /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"")
        return False


def install_python_via_installer():
    """通过 python.org 安装包安装 Python(不需要 sudo)"""
    print("\n正在下载 Python 安装包...")
    print("(这可能需要几分钟,取决于网速)\n")

    dmg_url = "https://www.python.org/ftp/python/3.13.0/python-3.13.0-macos11.pkg"
    dmg_path = "/tmp/python-installer.pkg"

    ok, _ = run_cmd(f'curl -L -o "{dmg_path}" "{dmg_url}"', check=False)
    if not ok:
        print("  ❌ 下载失败,请检查网络连接")
        return False

    print("  ✅ 下载完成,正在打开安装程序...")
    print("\n" + "=" * 50)
    print("  请在弹出的安装程序中:")
    print("  1. 点击「继续」")
    print("  2. 阅读许可协议,点击「继续」→「同意」")
    print("  3. 选择安装位置,点击「安装」")
    print("  4. 输入电脑密码(如果有)")
    print("  5. 等待安装完成,点击「关闭」")
    print("=" * 50)
    print("\n安装完成后,回到此窗口按回车键继续...")
    print("(或者输入 q 退出,稍后手动安装)")

    response = input("\n按回车继续,或输入 q 退出: ").strip().lower()
    if response == 'q':
        return False

    run_cmd(f'open "{dmg_path}"', check=False)

    input("\n安装完成后,按回车继续...")
    return True


def install_python():
    """安装 Python"""
    print("\n" + "=" * 50)
    print("正在安装 Python...")
    print("=" * 50)

    success, _ = run_cmd("which brew")
    if not success:
        print("  ❌ 未检测到 Homebrew")

        print("\n尝试通过安装包安装 Python(不需要 sudo)...")
        if install_python_via_installer():
            ok, _ = run_cmd("which python3", check=False)
            if ok:
                print("  ✅ Python 安装成功!")
                return True

        print("\n正在安装 Homebrew 作为备选...")
        if not install_homebrew():
            print("\n⚠️ 无法自动安装 Python")
            print("请手动安装: https://www.python.org/downloads/")
            return False

        print("\n重新检测 Homebrew...")
        success, _ = run_cmd("which brew")
        if not success:
            print("  ❌ Homebrew 安装失败")
            return False

    print("使用 Homebrew 安装 Python...")
    ok, msg = run_cmd("brew install python", check=False)
    if ok:
        print("  ✅ Python 安装成功!")
        return True
    else:
        print(f"  ⚠️ Homebrew 安装 Python 失败")
        print("尝试通过安装包安装...")

        if install_python_via_installer():
            ok, _ = run_cmd("which python3", check=False)
            if ok:
                print("  ✅ Python 安装成功!")
                return True

        return False


def install_dependencies():
    """安装脚本依赖"""
    print("\n正在安装依赖 (httpx, websockets)...")

    pip_cmd = "pip" if platform.system() == "Windows" else "pip3"
    deps = ["httpx", "websockets"]
    for dep in deps:
        ok, _ = run_cmd(f"{pip_cmd} install {dep}")
        if ok:
            print(f"  ✅ {dep} 安装成功")
        else:
            print(f"  ❌ {dep} 安装失败")
            return False
    return True


def check_workbuddy_installed():
    """检查 WorkBuddy 是否安装"""
    paths = [
        Path("/Applications/WorkBuddy.app"),
        Path.home() / "Applications/WorkBuddy.app",
        # Windows paths
        Path(os.path.expandvars(r"%LOCALAPPDATA%\Programs\WorkBuddy\WorkBuddy.exe")),
        Path(os.path.expandvars(r"%ProgramFiles%\WorkBuddy\WorkBuddy.exe")),
        Path(os.path.expandvars(r"%ProgramFiles(x86)%\WorkBuddy\WorkBuddy.exe")),
        Path(r"D:\Program Files\WorkBuddy\WorkBuddy.exe"),
        Path(r"E:\Program Files\WorkBuddy\WorkBuddy.exe"),
    ]
    for p in paths:
        if p.exists():
            return True, p
    return False, None


def check_workbuddy_running():
    """检查 WorkBuddy 是否正在运行(调试模式)"""
    try:
        import httpx
        resp = httpx.get("http://127.0.0.1:9222/json", timeout=2)
        if resp.status_code == 200:
            return True
    except:
        pass
    return False


def start_workbuddy_debug():
    """启动 WorkBuddy 调试模式"""
    print("\n正在启动 WorkBuddy(调试模式)...")

    if platform.system() == "Windows":
        # Find WorkBuddy on Windows
        candidates = [
            os.path.expandvars(r"%LOCALAPPDATA%\Programs\WorkBuddy\WorkBuddy.exe"),
            os.path.expandvars(r"%ProgramFiles%\WorkBuddy\WorkBuddy.exe"),
            os.path.expandvars(r"%ProgramFiles(x86)%\WorkBuddy\WorkBuddy.exe"),
            r"D:\Program Files\WorkBuddy\WorkBuddy.exe",
            r"E:\Program Files\WorkBuddy\WorkBuddy.exe",
        ]
        workbuddy_path = next((p for p in candidates if os.path.exists(p)), None)
        if not workbuddy_path:
            print("  ❌ 找不到 WorkBuddy,请手动启动"  )
            print("  → 关闭 WorkBuddy,然后重新打开"  )
            print("  → 或者:Win+R 运行:workbuddy --remote-debugging-port=9222"  )
            return False
        cmd = f'"{workbuddy_path}" --remote-debugging-port=9222'
    else:
        workbuddy_path = "/Applications/WorkBuddy.app/Contents/MacOS/Electron"
        cmd = f'"{workbuddy_path}" --remote-debugging-port=9222'

    try:
        subprocess.Popen(cmd, shell=True)
        print("  ✅ WorkBuddy 已启动")
        print("\n等待 WorkBuddy 完全加载(5秒)...")
        time.sleep(5)
        return True
    except Exception as e:
        print(f"  ❌ 启动失败: {e}")
        return False


def check_requirements():
    """检查前置条件"""
    print("\n[检查 1/4] 检测 Python...")
    if not check_python():
        if not install_python():
            return False

    print("\n[检查 2/4] 安装依赖...")
    if not install_dependencies():
        return False

    print("\n[检查 3/4] 检测 WorkBuddy...")
    installed, path = check_workbuddy_installed()
    if not installed:
        print("  ❌ WorkBuddy 未安装")
        print("  请先安装 WorkBuddy: https://workbuddy.com/download")
        return False
    print(f"  ✅ WorkBuddy 已安装: {path}")

    print("\n[检查 4/4] 检测 WorkBuddy 运行状态...")
    if check_workbuddy_running():
        print("  ✅ WorkBuddy 已运行(调试模式)")
    else:
        print("  ⚠️ WorkBuddy 未运行,正在启动...")
        if not start_workbuddy_debug():
            return False

    return True


async def extract_token():
    """从 WorkBuddy 提取 Token"""
    import httpx
    import websockets

    print("\n正在连接 WorkBuddy...")

    async with httpx.AsyncClient() as client:
        resp = await client.get("http://127.0.0.1:9222/json", timeout=5)
        targets = resp.json()

    print(f"  ✅ 找到 {len(targets)} 个页面")

    ws_url = None
    for t in targets:
        if t.get("type") == "page" and "workbench" in t.get("url", ""):
            ws_url = t.get("webSocketDebuggerUrl")
            break

    if not ws_url:
        for t in targets:
            if t.get("type") == "page":
                ws_url = t.get("webSocketDebuggerUrl")
                break

    if not ws_url:
        raise Exception("未找到 WorkBuddy 页面")

    print("  ✅ 已找到 WorkBuddy 页面")
    print("\n正在提取 Token...")

    async with websockets.connect(ws_url, ping_timeout=30) as ws:
        cmd = {
            "id": 1,
            "method": "Runtime.evaluate",
            "params": {
                "expression": """

                    (async () => {

                        try {

                            const s = await window.vscode.ipcRenderer.invoke(

                                'vscode:genie:auth:getSession'

                            );

                            return JSON.stringify(s);

                        } catch(e) {

                            return JSON.stringify({error: e.message});

                        }

                    })()

                """,
                "awaitPromise": True,
                "returnByValue": True,
            },
        }
        await ws.send(json.dumps(cmd))
        result = json.loads(await asyncio.wait_for(ws.recv(), timeout=30))

    value = result.get("result", {}).get("result", {}).get("value", "")
    if not value:
        raise Exception("CDP 返回为空")

    session = json.loads(value)
    if session.get("error"):
        raise Exception(f"CDP 错误: {session['error']}")

    return session


def save_token(access_token, refresh_token):
    """保存 Token 到桌面"""
    desktop = Path.home() / "Desktop"
    output_file = desktop / "token.txt"

    content = f"""WorkBuddy Token

生成时间: {time.strftime("%Y-%m-%d %H:%M:%S")}



access_token={access_token}

refresh_token={refresh_token}

"""

    output_file.write_text(content, encoding="utf-8")
    return output_file


def main():
    print("=" * 50)
    print("  WorkBuddy Token 提取工具")
    print("=" * 50)
    print("\n正在检测环境...\n")

    if not check_requirements():
        input("\n按回车键退出...")
        sys.exit(1)

    try:
        session = asyncio.run(extract_token())
    except Exception as e:
        print(f"\n❌ 提取失败: {e}")
        print("\n请确保:")
        print("  1. WorkBuddy 已登录")
        print("  2. 重新运行此脚本")
        input("\n按回车键退出...")
        sys.exit(1)

    auth = session.get("auth", session)
    access_token = auth.get("accessToken", "")
    refresh_token = auth.get("refreshToken", "")

    if not access_token:
        print("\n❌ 未获取到 accessToken")
        print("请确保 WorkBuddy 已登录 AI 功能")
        input("\n按回车键退出...")
        sys.exit(1)

    try:
        output_file = save_token(access_token, refresh_token)
    except Exception as e:
        print(f"\n❌ 保存失败: {e}")
        input("\n按回车键退出...")
        sys.exit(1)

    print("\n" + "=" * 50)
    print("✅ 成功!")
    print("=" * 50)
    print(f"\n📄 Token 已保存到桌面:")
    print(f"   {output_file}")
    print(f"\n🔑 access_token:  {access_token[:30]}...")
    print(f"🔑 refresh_token: {refresh_token[:30] if refresh_token else 'N/A'}...")
    print("\n" + "=" * 50)

    input("\n按回车键退出...")


if __name__ == "__main__":
    main()