dsh-workbuddy-xdpool 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -0
- package/README.en.md +112 -45
- package/README.md +104 -53
- package/assets/automation-panel.png +0 -0
- package/assets/settings-card.png +0 -0
- package/lib/bin.js +37 -7
- package/lib/client.js +23 -7
- package/lib/index.d.ts +37 -0
- package/lib/index.js +37 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,53 @@
|
|
|
4
4
|
|
|
5
5
|
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
6
6
|
|
|
7
|
+
## 1.3.0 (2026-09-23)
|
|
8
|
+
|
|
9
|
+
上一版把八类任务链接了进去,这一版修的是**「接进去了但你看不见」**的问题——功能在跑,界面上却没显示,等于白做。
|
|
10
|
+
|
|
11
|
+
### 猫猫旅行一天只跑一趟,等于坏了一半
|
|
12
|
+
|
|
13
|
+
旅行的流程是「派出去 → 回来领奖」,需要**两趟**。原来默认时段只配了 12:00 一个点,意味着猫早上出去之后,**要等到第二天**才有人管它。
|
|
14
|
+
|
|
15
|
+
改成 **09:00 + 21:00 两趟**(早上派出去,晚上回来领)。同时把每个任务的「今天跑过了」判断从**按日期**改成**按时间点**——按日期判断会把晚上那趟直接吞掉,这个守卫跟多时点本身是冲突的。单时点任务(签到、上报、任务奖励、连登)行为不变,同一小时内重复检查仍然不会重复跑。
|
|
16
|
+
|
|
17
|
+
> 参考项目的默认值就是 `[9, 21]`,注释里写的理由是「一趟派出 + 一趟领奖闭环」。
|
|
18
|
+
|
|
19
|
+
### 卡片现在告诉你「具体领到了什么」
|
|
20
|
+
|
|
21
|
+
原来每个任务只显示「日期 · 账号数」,回答不了「我最在意的那个任务领到了没」。
|
|
22
|
+
|
|
23
|
+
现在会**列出这一轮实际领到的奖励名**:
|
|
24
|
+
|
|
25
|
+
- 任务奖励 → 列出台任务标题(如「体验设计创意模式」「召唤 3 次专家团」)
|
|
26
|
+
- 每日签到 → `签到 +100`
|
|
27
|
+
- 猫猫旅行 → `猫猫旅行 +10`
|
|
28
|
+
|
|
29
|
+
连登奖励还没到解锁天数时,会显示**还差几天**(如 `7d in 4d`)——所有档位都是未解锁属于正常状态,但只写「未解锁」会让人以为坏了。
|
|
30
|
+
|
|
31
|
+
### 修掉「猫猫旅行永远不显示」
|
|
32
|
+
|
|
33
|
+
有个真 bug:积分自动化面板里只显示签到 / 上报 / 任务 / 连登四行,**猫猫旅行那行永远不出现**,尽管它确实在跑。
|
|
34
|
+
|
|
35
|
+
根因是那行任务的判断逻辑里,**列表本身就是缺的**——界面渲染一行一个任务,而列表里没有 travel,分支里也没有,类型定义里同样没有。这类「加了功能忘了加列表」的失败模式是**静默的**:任务照跑,用户看不见,也不会报错。
|
|
36
|
+
|
|
37
|
+
除了补齐三处,还加了个**防回归测试**:卡片的任务列表必须和调度器的任务列表逐项相等、顺序一致。这个不变量之前没人守。
|
|
38
|
+
|
|
39
|
+
### 其它
|
|
40
|
+
|
|
41
|
+
- 行内文案「未排程 / 尚未执行」改成「当天不跑 / 还没跑过」,原来的说法不好懂。
|
|
42
|
+
- 补上中英两份缺失的「猫猫旅行」标签(之前那行显示的是原始 key)。
|
|
43
|
+
- README 重写(中英双语):按「多账号池」和「积分自动化」两块组织,把 13 个任务名列出来、实测数据写进去,并把几个踩坑结论翻译成大白话。
|
|
44
|
+
- 截图更新:卡片全貌换成含自动化面板的新版,另加一张自动化面板特写。
|
|
45
|
+
- 测试从 134 增至 139。
|
|
46
|
+
|
|
47
|
+
### 已知限制(未变)
|
|
48
|
+
|
|
49
|
+
- `Expert_Philanthropy`(公益专家)需要真实捐款,不做。
|
|
50
|
+
- `black_cat`(夜猫子)只在 23:00–08:00 计分且无积分奖励,不做。
|
|
51
|
+
- `Model_chat_GLM5.2` 与 `wb_wechat_oa_subscribe_task` 留待下个版本。
|
|
52
|
+
- `Expert_team_use_3` 偶发卡在 2/3(怀疑单账号当日额度,跨天恢复,未验证;新账号不受影响)。
|
|
53
|
+
|
|
7
54
|
## 1.2.0 (2026-09-23)
|
|
8
55
|
|
|
9
56
|
把成长中心剩下的**八类客户端任务**也接进自动化。这些任务在任务中心里写的是「升级桌面客户端后点击某个入口」,听起来只有人坐在真实客户端前才能完成;实际上计分器看的是**行为事件流**,只要事件形状对、指纹对,任务就会涨进度。这一轮把每条链都在真实账号上跑通并回读确认了计分。
|
package/README.en.md
CHANGED
|
@@ -9,36 +9,83 @@
|
|
|
9
9
|
|
|
10
10
|
English | [中文](./README.md)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Every account you've signed into the WorkBuddy desktop app, merged into one DSH model pool. However many accounts you've used, that's how many the pool holds — no forms, no manual import.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
An account gets rate-limited or runs out of credits? The request just moves to the next one that works. You keep asking; it keeps handling the rest.
|
|
15
15
|
|
|
16
|
-
**
|
|
16
|
+
**It also throws in a full points-automation suite**: check-ins, task rewards, streak redemption, the buddy trip — all the chores you'd otherwise click through every day, done in the background.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
> **How this differs from the single-account connectors**: plugins like `dsh-workbuddy-connect` handle one account at a time. XD Pool treats **multiple accounts as the normal case** — it doesn't pick favourites or ask you to import anything. Every sign-in snapshot on this machine goes into one shared pool, exposed as a single `workbuddy-xdpool` provider group, with automatic failover inside.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
## Screenshots
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
**The plugin card (Settings → Plugins → DSH WorkBuddy XD Pool)**
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+

|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
**The points-automation panel**
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
**Model picker (CN and global as two separate groups)**
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
**CN / global dual provider (separate accounts, credits and models, usable at the same time)**
|
|
35
|
+
|
|
36
|
+

|
|
27
37
|
|
|
28
38
|
## Features
|
|
29
39
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
- **
|
|
33
|
-
|
|
34
|
-
- **
|
|
35
|
-
|
|
36
|
-
- **
|
|
37
|
-
|
|
40
|
+
### 1. The multi-account pool
|
|
41
|
+
|
|
42
|
+
- **Zero config**: install it, turn it on, done. Every account signed into the WorkBuddy desktop app is discovered and pooled automatically — nothing to enter by hand.
|
|
43
|
+
|
|
44
|
+
- **Automatic failover**: the pool tracks each account's rate-limit state. Hit a 429 and that account cools down while later requests land on the next healthy one; it rejoins automatically once the cooldown ends. Requests only wait when every account is cooling.
|
|
45
|
+
|
|
46
|
+
- **Pool health at a glance**: the card shows how many accounts there are, how many are cooling, which one is next, plus each account's token expiry and cooldown countdown.
|
|
47
|
+
|
|
48
|
+
- **Live credit balances**: per-account credit packages (`package · remaining / total`) with a large total, refreshed from upstream as it changes.
|
|
49
|
+
|
|
50
|
+
- **An annotated model catalog**: pool models with their credit multiplier (e.g. `GLM-5.2 · x0.79`), free / limited-free / night-discount tags, image-input support and context window — all tracking upstream live.
|
|
51
|
+
|
|
52
|
+
- **CN / global auto-detection**: the upstream origin is picked per account from its login domain — a global sign-in (`workbuddy.ai`) goes to `www.workbuddy.ai`, CN (the default) to `copilot.tencent.com`. Both kinds can live in the same pool.
|
|
53
|
+
|
|
54
|
+
- **Manual controls when you want them**: re-detect accounts, clear all cooldowns, and daily check-in — on the card and in the CLI.
|
|
55
|
+
|
|
56
|
+
### 2. Points automation
|
|
57
|
+
|
|
58
|
+
One switch on the card, and the plugin works through your growth-centre routine for you. **On by default, and you can hit "Run now" to force a pass whenever you like.**
|
|
59
|
+
|
|
60
|
+
Five jobs:
|
|
61
|
+
|
|
62
|
+
| Job | Default time | What it does |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| Daily check-in | 09:00 | Collect today's check-in reward |
|
|
65
|
+
| Activity report | 10:00 | Report activity so the growth centre counts the day |
|
|
66
|
+
| Task rewards | 11:00 | Enrol in open tasks and collect every reward that's ready |
|
|
67
|
+
| Streak bonus | 12:00 | Redeem streak tiers and spend the lottery draws |
|
|
68
|
+
| Buddy trip | 09:00 · 21:00 | Send the cat out, collect it when it's back |
|
|
69
|
+
|
|
70
|
+
**The task-rewards pass covers 13 board tasks**, including the ones that read as "somebody has to sit at the desktop and click these menus":
|
|
71
|
+
|
|
72
|
+
> Browse inspiration · Use 5 templates · Try a hot skill · Apply the "Peacekeeper Elite" theme · Read the library · Summon 5 experts · Summon 3 expert teams · Try the Tencent Lighthouse expert · Open any assistant app · Enter the QQ teacher assistant · Create a design canvas · Create a scheduled task · Chat with the cat
|
|
73
|
+
|
|
74
|
+
Measured across four accounts, one pass collected **3300 credits and 135 energy**.
|
|
75
|
+
|
|
76
|
+
**The card tells you what a pass actually collected** — it lists the task names rather than reporting a bare count. The streak countdown is spelled out too ("7d in 4d"), so a locked tier doesn't look like a failure.
|
|
77
|
+
|
|
78
|
+
**"Earned today"** breaks the day down by source — task rewards, check-in, streak, buddy trip — and resets at midnight.
|
|
79
|
+
|
|
80
|
+
**Credit floor per account**: set a minimum balance and an account below it stops being given work, so you can keep some credits in reserve.
|
|
81
|
+
|
|
82
|
+
> **The global region doesn't show this panel** — that gateway has no growth system at all.
|
|
38
83
|
|
|
39
84
|
## Install
|
|
40
85
|
|
|
41
|
-
Prerequisite: WorkBuddy desktop app installed and signed in (the plugin reuses the
|
|
86
|
+
Prerequisite: the WorkBuddy desktop app installed and signed in (the plugin reuses the sign-in state it stores locally). Multi-account = sign in and out a few times in the desktop app; each sign-in is absorbed into the pool. Built against DSH Desktop host `0.1.2`.
|
|
87
|
+
|
|
88
|
+
> Compatible with the `0.1.1-rc.2` / `0.1.2` host line: the settings section installs via `settings.installSection` (0.1.2-rc.1+) or the earlier free-function form, whichever the host supports.
|
|
42
89
|
|
|
43
90
|
**Option A — install from npm (recommended)**
|
|
44
91
|
|
|
@@ -48,15 +95,15 @@ dsh plugin --profile desktop add dsh-workbuddy-xdpool
|
|
|
48
95
|
```
|
|
49
96
|
|
|
50
97
|
> npm is the fast path: the only dependency pulled in is the plugin itself (**roughly 1 package, a few seconds**).
|
|
51
|
-
> Installing from GitHub source
|
|
98
|
+
> Installing from the GitHub source drags in the dev dependencies (bundler, test runner, hundreds of packages) and is much slower.
|
|
52
99
|
|
|
53
|
-
**Option B — install from GitHub source**
|
|
100
|
+
**Option B — install from the GitHub source**
|
|
54
101
|
|
|
55
102
|
```sh
|
|
56
103
|
dsh plugin --profile desktop add github:XDTrees/dsh-workbuddy-xdpool
|
|
57
104
|
```
|
|
58
105
|
|
|
59
|
-
**Option C —
|
|
106
|
+
**Option C — register the bundle by hand**
|
|
60
107
|
|
|
61
108
|
```sh
|
|
62
109
|
# 1) install the package (npm or GitHub)
|
|
@@ -68,26 +115,28 @@ dsh plugin --profile desktop add dsh-workbuddy-xdpool
|
|
|
68
115
|
# 3) restart DSH Desktop
|
|
69
116
|
```
|
|
70
117
|
|
|
71
|
-
**
|
|
118
|
+
**Building locally (developers)**
|
|
72
119
|
|
|
73
120
|
```sh
|
|
74
121
|
pnpm install
|
|
75
|
-
pnpm build
|
|
76
|
-
pnpm test
|
|
77
|
-
pnpm typecheck
|
|
78
|
-
pnpm typecheck:client
|
|
122
|
+
pnpm build # produces lib/index.js + lib/index.d.ts + lib/bin.js + lib/client.js
|
|
123
|
+
pnpm test # 138 tests
|
|
124
|
+
pnpm typecheck # host side
|
|
125
|
+
pnpm typecheck:client # client side
|
|
79
126
|
```
|
|
80
127
|
|
|
81
|
-
> `
|
|
128
|
+
> **The build output is committed** (`lib/` is not gitignored), so a GitHub install needs no install-time script and never trips pnpm's "build scripts were blocked" prompt. **After changing `src/`, re-run `pnpm build` and commit `lib/` too** — otherwise users get the old build.
|
|
129
|
+
|
|
130
|
+
> Note: `pnpm install` wants pnpm 11 (`npx pnpm@11`), and may need `--config.confirmModulesPurge=false --config.minimumReleaseAge=0` — pnpm 11's default `minimumReleaseAge` supply-chain policy blocks just-published rc packages.
|
|
82
131
|
|
|
83
|
-
|
|
84
|
-
> no install-time script and never hits pnpm's "build scripts are blocked" prompt. **After changing
|
|
85
|
-
> `src/`, re-run `pnpm build` and commit `lib/` too**, or users would receive the old build.
|
|
132
|
+
Once installed: a **WorkBuddy XD Pool** group appears in the model picker, and Settings → Plugins → **DSH WorkBuddy XD Pool** shows pool health, each account's token / credits / check-in / cooldown state, the "Detect accounts again" and "Clear all cooldowns" buttons, and a check-in button per account.
|
|
86
133
|
|
|
87
|
-
|
|
134
|
+
It also works under the Web / TUI profiles (`--profile web` / `--profile dsh-tui`).
|
|
88
135
|
|
|
89
136
|
## CLI
|
|
90
137
|
|
|
138
|
+
All commands run through `dsh plugin --profile desktop exec dsh-workbuddy-xdpool <subcommand>`:
|
|
139
|
+
|
|
91
140
|
```sh
|
|
92
141
|
dsh plugin --profile desktop exec dsh-workbuddy-xdpool status # pool accounts/cooldown + shim state (--credits, --json, --rates)
|
|
93
142
|
dsh plugin --profile desktop exec dsh-workbuddy-xdpool accounts # discovered accounts (--json)
|
|
@@ -131,32 +180,50 @@ workbuddy-xdpool:
|
|
|
131
180
|
|
|
132
181
|
## Architecture
|
|
133
182
|
|
|
134
|
-
- **Host side** (`src
|
|
135
|
-
-
|
|
136
|
-
-
|
|
183
|
+
- **Host side** (`src/`, inside the DSH main process)
|
|
184
|
+
- `index.ts` — registers the `workbuddy-xdpool` provider, the `workbuddy-xdpool` settings section, the same-origin routes (status / re-scan / clear cooldowns / check-in / automation run / credit reserve), plus account discovery and catalog seeding.
|
|
185
|
+
- `accounts.ts` — `WorkBuddyAccountPool`: reads the desktop auth snapshots, 429 cooldowns, rotation and token refresh; account disabling and credit reserves live here too.
|
|
186
|
+
- `scheduler.ts` — the points-automation scheduler: runs five jobs on local time points (check-in / report / tasks / streak / travel), persists the daily earnings ledger, and backs the card's "Run now" button with the same code path.
|
|
187
|
+
- `task-events.ts` — builds the 13 task event chains. Each chain is plain data plus the fingerprint channel it must go out on (desktop or web); the tasks that need a REAL conversation (skill, experts) open one here to get the server-side id.
|
|
188
|
+
- `catalog.ts` / `upstream.ts` — the upstream client: model catalog (with per-model multipliers and free / image tags), credits, check-in, and every automation endpoint, switching CN/global by credential domain.
|
|
189
|
+
- `web-status.ts` / `status-paths.ts` — the same-origin status document and routes the card reads. Mutations are gated on POST + loopback origin + an explicit `accountId`.
|
|
190
|
+
- `bin.ts` — the CLI above.
|
|
191
|
+
- **Client** (`src/client/`, the browser card loaded via `dsh.client`)
|
|
192
|
+
The collapsible shell reuses the host's `dsm-plugin-card*` style language (`--dsw-alias-*` theme tokens); content classes are namespaced `dsm-workbuddy-xdpool-*`, and copy lives under the `settings.workbuddy-xdpool` namespace.
|
|
193
|
+
- **Build**
|
|
194
|
+
`tsdown` produces `lib/index.js` (host entry) + `lib/index.d.ts` (types) + `lib/bin.js` (CLI) + `lib/client.js` (CJS browser bundle wrapped in `window.__ModuleLoader__.load`). All four are committed, so an install needs no build-time script.
|
|
137
195
|
|
|
138
196
|
## Known limitations
|
|
139
197
|
|
|
140
|
-
- **Only accounts on
|
|
141
|
-
|
|
142
|
-
-
|
|
198
|
+
- **Only accounts on THIS machine's desktop app**: the pool cannot — and will not — sign you in or scan a QR code (tokens are minted by the WorkBuddy desktop app's own Tencent SSO and bound to the device). Adding an account = signing in on the desktop app; XD Pool absorbs it.
|
|
199
|
+
|
|
200
|
+
- **A few automation tasks are deliberately not implemented**
|
|
201
|
+
- `Expert_Philanthropy` (charity expert): requires a real donation; there is no way around it.
|
|
202
|
+
- `black_cat` (night owl): only scores between 23:00 and 08:00, and pays **no credits** — all-nighters for nothing.
|
|
203
|
+
- `Model_chat_GLM5.2` (chat with a specific model) and `wb_wechat_oa_subscribe_task` (follow the official account): the path is mapped out, deferred to the next release.
|
|
204
|
+
|
|
205
|
+
- **`Expert_team_use_3` occasionally sticks at 2/3**: on one account, after two expert teams had been used that day, the third would not register (using a different, unused team didn't help either). Suspected per-account daily quota that resets the next day, unconfirmed. **Fresh accounts are unaffected** (measured 0/3 → 3/3).
|
|
206
|
+
|
|
207
|
+
- **Depends on WorkBuddy's client APIs** (not an official public API), so a WorkBuddy update may require a matching plugin update. If an account's refresh token lapses, sign in again on the desktop.
|
|
208
|
+
|
|
209
|
+
- If your Windows and Linux usernames differ and the Windows environment variable doesn't reach WSL, point `WORKBUDDY_AUTH_FILE` (or `authFile`) at the real location.
|
|
143
210
|
|
|
144
211
|
## Disclaimer
|
|
145
212
|
|
|
146
|
-
-
|
|
147
|
-
- You are responsible for complying with WorkBuddy's terms of service
|
|
148
|
-
- The authors
|
|
149
|
-
- This project is not affiliated with,
|
|
213
|
+
- This project is **for personal study and research only**. It drives only your own WorkBuddy accounts from your own machine — do not use it commercially or beyond reasonable personal use.
|
|
214
|
+
- You are responsible for complying with WorkBuddy's terms of service. Any consequences of using this project (including but not limited to account restrictions, cleared balances, or service interruption) are yours to bear.
|
|
215
|
+
- The authors accept no liability for any direct or indirect loss arising from the use or misuse of this project.
|
|
216
|
+
- This project is not affiliated with, authorised by, or endorsed by Tencent, WorkBuddy, or DeepSeek. Product names appear only to describe compatibility; trademarks belong to their respective owners.
|
|
150
217
|
|
|
151
218
|
## Acknowledgments
|
|
152
219
|
|
|
153
|
-
This project
|
|
220
|
+
This project draws on the following public projects and keeps their copyright notices as their licences require. What was taken is **design approach and established findings**; the code is an independent implementation. The modules that lean on a specific source say so in their file headers:
|
|
154
221
|
|
|
155
|
-
- [corrinehu/dsh-workbuddy-connect](https://github.com/corrinehu/dsh-workbuddy-connect) (MIT) — the
|
|
156
|
-
- [dingminhua/dsh-connect-workbuddy](https://github.com/dingminhua/dsh-connect-workbuddy) (MIT, Copyright (c) 2026 LaoDing) — the reference for the `dsm-plugin-card*` card style language and `--dsw-alias-*` theme tokens;
|
|
157
|
-
- [Sliverkiss/workbuddy2api](https://github.com/Sliverkiss/workbuddy2api) (MIT) — reference
|
|
222
|
+
- [corrinehu/dsh-workbuddy-connect](https://github.com/corrinehu/dsh-workbuddy-connect) (MIT) — the primary reference for settings-section registration (`settings.installSection`) and the DSH plugin structure, the client card loading mechanism, and desktop credential refresh plus loopback-shim hardening. This project follows its "host mounts the card via installSection" path.
|
|
223
|
+
- [dingminhua/dsh-connect-workbuddy](https://github.com/dingminhua/dsh-connect-workbuddy) (MIT, Copyright (c) 2026 LaoDing) — the reference implementation for the `dsm-plugin-card*` card style language and `--dsw-alias-*` theme tokens; **daily check-in** (`/v2/billing/meter/checkin-activity-status` and `/v2/billing/meter/daily-checkin`), the credit-package aggregation rules (monthly vs one-off packs), and picking the upstream origin per credential `domain` all follow interface shapes that project verified.
|
|
224
|
+
- [Sliverkiss/workbuddy2api](https://github.com/Sliverkiss/workbuddy2api) (MIT) — the reference for the WorkBuddy upstream protocol (`copilot.tencent.com` wire behaviour) and the credits APIs; **points automation** (growth-centre check-in, activity report, streak redemption, the buddy-trip state machine, the 13 task event chains, and the expert summon chains) was ported wholesale from that project's Go reverse-engineering, including the scoring criteria and measured conclusions behind every event chain.
|
|
158
225
|
|
|
159
|
-
All
|
|
226
|
+
All copyright in the above belongs to their respective authors. This project uses a **reference-the-approach, implement-independently** method and does not copy any reference project's source wholesale. If anything is mis-attributed or missing, please open an issue.
|
|
160
227
|
|
|
161
228
|
## License
|
|
162
229
|
|
package/README.md
CHANGED
|
@@ -9,15 +9,25 @@
|
|
|
9
9
|
|
|
10
10
|
[English](./README.en.md) | 中文
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
把 WorkBuddy 桌面 App 里登录过的**所有账号**,合成一个 DSH 模型池。你在 WorkBuddy 里登过几个号,池里就有几个号——不用手动填表,不用一个个录入。
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
哪个号被限流了、积分用光了,请求自动换到下一个能用的号上去。你只管问,剩下的它自己处理。
|
|
15
|
+
|
|
16
|
+
**另外附送一整套「积分自动化」**:签到、领任务奖励、连登兑换、开猫猫旅行……这些每天都要手动点一遍的活儿,插件在后台替你干完了。
|
|
17
|
+
|
|
18
|
+
> **和单账号连接插件的区别**:`dsh-workbuddy-connect` 那类插件是「一次一个账号」。XD Pool 把**多账号当默认情况**——不挑号、不手动导入,本机 WorkBuddy 所有历史登录快照全部收进一个共享池,对外用一个 `workbuddy-xdpool` provider 分组,池内自动容错。
|
|
19
|
+
|
|
20
|
+
## 先看几张图
|
|
15
21
|
|
|
16
22
|
**插件配置卡片(设置 → 插件 → DSH WorkBuddy XD Pool)**
|
|
17
23
|
|
|
18
|
-

|
|
19
25
|
|
|
20
|
-
|
|
26
|
+
**积分自动化面板**
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+
|
|
30
|
+
**模型选择器(国内版 / 国际版 两个独立分组)**
|
|
21
31
|
|
|
22
32
|

|
|
23
33
|
|
|
@@ -27,27 +37,55 @@
|
|
|
27
37
|
|
|
28
38
|
## 功能
|
|
29
39
|
|
|
30
|
-
|
|
40
|
+
### 一、多账号池
|
|
41
|
+
|
|
42
|
+
- **零配置**:装上、打开,就完事了。WorkBuddy 桌面 App 里每个登过的账号都会被自动发现并入池,不需要在插件里录任何东西。
|
|
31
43
|
|
|
32
|
-
-
|
|
44
|
+
- **自动容错换号**:池子记着每个账号的限流状态。某个号触发 429 就冷却它,后面的请求自动落到下一个健康的号上;冷却结束自动恢复。所有号都在冷却时,请求才排队等待。
|
|
33
45
|
|
|
34
|
-
-
|
|
46
|
+
- **池健康一眼看清**:卡片显示「几个账号 / 几个在冷却」「下一个会轮到谁」,以及每个账号的令牌有效期和冷却倒计时。
|
|
35
47
|
|
|
36
|
-
-
|
|
48
|
+
- **剩余积分实时可见**:按账号列出积分包(`套餐名 · 剩余 / 总量`)和大字合计,跟着上游实时刷新。
|
|
37
49
|
|
|
38
|
-
-
|
|
50
|
+
- **模型目录带标注**:列出池里能用的模型,附带积分倍率(如 `GLM-5.2 · x0.79`)、免费 / 限时免费 / 夜间折扣标签、能否收图和上下文窗口大小,全部跟随上游实时更新。
|
|
39
51
|
|
|
40
|
-
-
|
|
52
|
+
- **国内版 / 国际版自动适配**:按账号凭据里的登录域名自动选上游——国际版登录(`workbuddy.ai`)走 `www.workbuddy.ai`,国内版(默认)走 `copilot.tencent.com`。两种账号可以混在同一个池里。
|
|
41
53
|
|
|
42
|
-
-
|
|
54
|
+
- **想手动做点啥也行**:卡片和命令行都提供「重新检测账号」「清除所有冷却」「每日签到」三个操作。
|
|
55
|
+
|
|
56
|
+
### 二、积分自动化
|
|
57
|
+
|
|
58
|
+
卡片上一个开关,插件在后台把你成长中心的日常动作全做掉。**默认全自动,也可以随时点「立即运行」手动跑一轮。**
|
|
59
|
+
|
|
60
|
+
它管这五件事:
|
|
61
|
+
|
|
62
|
+
| 任务 | 默认时间 | 干什么 |
|
|
63
|
+
| --- | --- | --- |
|
|
64
|
+
| 每日签到 | 09:00 | 领取当天签到奖励 |
|
|
65
|
+
| 活跃上报 | 10:00 | 报个到,让成长中心知道你还在用 |
|
|
66
|
+
| 任务奖励 | 11:00 | 把任务中心的奖励该报名的报名、该领的领掉 |
|
|
67
|
+
| 连登奖励 | 12:00 | 连登档位兑换 + 抽奖 |
|
|
68
|
+
| 猫猫旅行 | 09:00 · 21:00 | 把猫派出去、回来领奖励 |
|
|
43
69
|
|
|
44
|
-
|
|
70
|
+
**「任务奖励」这一项覆盖了 13 个任务**,包括那些看起来非得本人坐在电脑前点鼠标才能完成的:
|
|
71
|
+
|
|
72
|
+
> 探索优秀灵感 · 使用 5 个模板 · 尝鲜热门技能 · 换「和平精英」主题 · 逛资料库 · 召唤 5 次专家 · 召唤 3 次专家团 · 体验腾讯轻量云专家 · 进入任一小助手应用 · 进入企鹅教师助手 · 设计创意模式建画布 · 创建定时任务 · 猫猫对话
|
|
73
|
+
|
|
74
|
+
实测一轮跑下来,四个账号合计领到 **3300 积分 + 135 能量**。
|
|
75
|
+
|
|
76
|
+
**卡片上会告诉你这一轮具体领到了什么**——不是只写「领了 8 个任务」,而是把任务名字列出来。连登还差几天解锁也会写清楚(比如「还差 4 天解锁 7 天档」),免得你以为是坏了。
|
|
77
|
+
|
|
78
|
+
**关于「今日收益」**:卡片按来源分四行显示——任务奖励、签到、连登、旅行。今天赚了多少一眼看到,跨天自动清零。
|
|
79
|
+
|
|
80
|
+
**关于保留积分**:可以给每个账号设一个积分下限,余额低于这个数的账号就不派活了,省着点用。
|
|
81
|
+
|
|
82
|
+
> **国际版不显示这个面板**——那边的网关压根没有积分系统。
|
|
45
83
|
|
|
46
84
|
## 安装
|
|
47
85
|
|
|
48
|
-
|
|
86
|
+
前置条件:装好 WorkBuddy 桌面 App 并登录(插件复用它存在本机的登录状态)。多账号 = 在桌面 App 里换着登几次,每次登录都会被自动吸进池里。已针对 DSH Desktop host `0.1.2` 适配。
|
|
49
87
|
|
|
50
|
-
>
|
|
88
|
+
> 兼容 host `0.1.1-rc.2` / `0.1.2` 系列:安装设置节时会按 host 能力自动选择 `settings.installSection`(0.1.2-rc.1+)或更早的自由函数写法。
|
|
51
89
|
|
|
52
90
|
**方式一:从 npm 安装(推荐)**
|
|
53
91
|
|
|
@@ -56,8 +94,8 @@
|
|
|
56
94
|
dsh plugin --profile desktop add dsh-workbuddy-xdpool
|
|
57
95
|
```
|
|
58
96
|
|
|
59
|
-
> 推荐 npm
|
|
60
|
-
> 从 GitHub
|
|
97
|
+
> 推荐 npm:需要拉取的依赖只有插件自己(**约 1 个包,几秒搞定**)。
|
|
98
|
+
> 从 GitHub 源码装会连带装开发依赖(构建器、测试框架等几百个包),慢得多。
|
|
61
99
|
|
|
62
100
|
**方式二:从 GitHub 源码安装**
|
|
63
101
|
|
|
@@ -68,74 +106,74 @@ dsh plugin --profile desktop add github:XDTrees/dsh-workbuddy-xdpool
|
|
|
68
106
|
**方式三:手动注册 bundle**
|
|
69
107
|
|
|
70
108
|
```sh
|
|
71
|
-
# 1)
|
|
109
|
+
# 1) 先装包(npm 或 GitHub 任选)
|
|
72
110
|
dsh plugin --profile desktop add dsh-workbuddy-xdpool
|
|
73
111
|
|
|
74
112
|
# 2) 注册 bundle:编辑 ~/.dsh/profiles/desktop/package.json,
|
|
75
|
-
# 在 "dsh" → "profile" → "bundles"
|
|
113
|
+
# 在 "dsh" → "profile" → "bundles" 数组末尾加上 "dsh-workbuddy-xdpool"
|
|
76
114
|
|
|
77
115
|
# 3) 重启 DSH Desktop
|
|
78
116
|
```
|
|
79
117
|
|
|
80
|
-
|
|
118
|
+
**本地构建(开发者)**
|
|
81
119
|
|
|
82
120
|
```sh
|
|
83
121
|
pnpm install
|
|
84
|
-
pnpm build
|
|
85
|
-
pnpm test
|
|
86
|
-
pnpm typecheck
|
|
87
|
-
pnpm typecheck:client #
|
|
122
|
+
pnpm build # 产出 lib/index.js + lib/index.d.ts + lib/bin.js + lib/client.js
|
|
123
|
+
pnpm test # 138 项测试
|
|
124
|
+
pnpm typecheck # 宿主侧类型检查
|
|
125
|
+
pnpm typecheck:client # 客户端类型检查
|
|
88
126
|
```
|
|
89
127
|
|
|
90
|
-
> **构建产物已随仓库提交**(`lib/`
|
|
128
|
+
> **构建产物已随仓库提交**(`lib/` 不在 gitignore 里),所以从 GitHub 装不需要任何安装期脚本,也不会弹 pnpm 那句「构建脚本被拦截,请放行」。**改了 `src/` 记得重新 `pnpm build` 并把 `lib/` 一起提交**,否则用户拿到的是旧产物。
|
|
91
129
|
|
|
92
|
-
> 注意:`pnpm install`
|
|
130
|
+
> 注意:`pnpm install` 要用 pnpm 11(`npx pnpm@11`),必要时加 `--config.confirmModulesPurge=false --config.minimumReleaseAge=0`——pnpm 11 默认的 `minimumReleaseAge` 供应链年龄策略会拦下刚发布的 rc 包。
|
|
93
131
|
|
|
94
|
-
|
|
132
|
+
装完以后:模型选择器里会出现 **WorkBuddy XD Pool** 分组;设置 → 插件 → **DSH WorkBuddy XD Pool** 能看池健康、各账号的令牌 / 积分 / 签到 / 冷却状态,还有「重新检测账号」「清除所有冷却」按钮和每个账号的签到按钮。
|
|
95
133
|
|
|
96
|
-
|
|
134
|
+
Web / TUI profile 也能用(`--profile web` / `--profile dsh-tui`)。
|
|
97
135
|
|
|
98
136
|
## 命令行
|
|
99
137
|
|
|
100
138
|
统一用 `dsh plugin --profile desktop exec dsh-workbuddy-xdpool <子命令>` 调用:
|
|
101
139
|
|
|
102
140
|
```sh
|
|
103
|
-
dsh plugin --profile desktop exec dsh-workbuddy-xdpool status #
|
|
104
|
-
dsh plugin --profile desktop exec dsh-workbuddy-xdpool accounts #
|
|
105
|
-
dsh plugin --profile desktop exec dsh-workbuddy-xdpool doctor #
|
|
106
|
-
dsh plugin --profile desktop exec dsh-workbuddy-xdpool reset #
|
|
107
|
-
dsh plugin --profile desktop exec dsh-workbuddy-xdpool checkin #
|
|
141
|
+
dsh plugin --profile desktop exec dsh-workbuddy-xdpool status # 池里几个号 / 几个冷却 + shim 状态(--credits 查积分、--json 机器可读、--rates 看倍率)
|
|
142
|
+
dsh plugin --profile desktop exec dsh-workbuddy-xdpool accounts # 已发现的账号(--json)
|
|
143
|
+
dsh plugin --profile desktop exec dsh-workbuddy-xdpool doctor # 诊断发现 / 冷却 / 上游连通性
|
|
144
|
+
dsh plugin --profile desktop exec dsh-workbuddy-xdpool reset # 立刻清掉所有 429 冷却
|
|
145
|
+
dsh plugin --profile desktop exec dsh-workbuddy-xdpool checkin # 查每个账号今天签到了没(--json 机器可读)
|
|
108
146
|
dsh plugin --profile desktop exec dsh-workbuddy-xdpool checkin all
|
|
109
|
-
#
|
|
110
|
-
dsh plugin --profile desktop exec dsh-workbuddy-xdpool login #
|
|
147
|
+
# 领掉所有账号今天的签到奖励;也可以只传一个账号标签领单个
|
|
148
|
+
dsh plugin --profile desktop exec dsh-workbuddy-xdpool login # 教你怎么在桌面再加一个号进池
|
|
111
149
|
```
|
|
112
150
|
|
|
113
151
|
## 池里怎么多账号?
|
|
114
152
|
|
|
115
|
-
|
|
153
|
+
池子走**自动发现**:WorkBuddy 桌面 App 每次登录都会在本机留一个带令牌的历史快照,XD Pool 扫描这些快照,把每个账号都收进池。所以多账号 = 在桌面 App 里换着登几次,之后点卡片上的「重新检测账号」或者重启 DSH,新号就自动进池了。
|
|
116
154
|
|
|
117
|
-
|
|
155
|
+
如果你想给桌面 App 之外的一次登录做个**显式快照**(比如临时固定某个号做验证),也可以手动导入:
|
|
118
156
|
|
|
119
157
|
```sh
|
|
120
158
|
# 在 WorkBuddy 桌面 App 登录账号后(key 自己起名):
|
|
121
159
|
dsh plugin --profile desktop exec dsh-workbuddy-xdpool import myKey
|
|
122
|
-
#
|
|
160
|
+
# 查看 / 删除已导入的快照:
|
|
123
161
|
dsh plugin --profile desktop exec dsh-workbuddy-xdpool accounts
|
|
124
162
|
dsh plugin --profile desktop exec dsh-workbuddy-xdpool remove myKey
|
|
125
163
|
```
|
|
126
164
|
|
|
127
|
-
|
|
165
|
+
导入的快照以 key 的 **MD5 前 8 位**命名,放在 `~/.dsh/.workbuddy-xdpool/`(key 本身记在文件里),中文、带 `/`、带空格的 key 都安全。长期使用靠 refresh token 自动续期;失效了就回桌面重新登录,再 `import <key> --force` 覆盖。
|
|
128
166
|
|
|
129
167
|
## 配置
|
|
130
168
|
|
|
131
|
-
|
|
169
|
+
池的配置走插件设置节(`settings.workbuddy-xdpool`),模型设置页里能改,改完立即生效:
|
|
132
170
|
|
|
133
171
|
| 字段 | 说明 | 默认 |
|
|
134
172
|
| --- | --- | --- |
|
|
135
|
-
| `authFile` | 覆盖 WorkBuddy 桌面 auth
|
|
173
|
+
| `authFile` | 覆盖 WorkBuddy 桌面 auth 文件路径(跨平台自动探测出问题时用,等同于 `WORKBUDDY_AUTH_FILE`) | 自动探测 |
|
|
136
174
|
| `cooldownMs` | 单账号 429 冷却时长(毫秒) | `60000` |
|
|
137
175
|
|
|
138
|
-
|
|
176
|
+
也可以直接写进 `~/.dsh/settings.yaml`:
|
|
139
177
|
|
|
140
178
|
```yaml
|
|
141
179
|
workbuddy-xdpool:
|
|
@@ -144,20 +182,33 @@ workbuddy-xdpool:
|
|
|
144
182
|
|
|
145
183
|
## 架构
|
|
146
184
|
|
|
147
|
-
- **宿主侧**(`src
|
|
148
|
-
- `index.ts` —— 注册 `workbuddy-xdpool` provider、`workbuddy-xdpool`
|
|
149
|
-
- `accounts.ts` —— `WorkBuddyAccountPool`:读本机 WorkBuddy 桌面 auth 快照、429
|
|
150
|
-
- `
|
|
151
|
-
- `
|
|
152
|
-
- `
|
|
153
|
-
-
|
|
154
|
-
-
|
|
185
|
+
- **宿主侧**(`src/`,跑在 DSH 主进程里)
|
|
186
|
+
- `index.ts` —— 注册 `workbuddy-xdpool` provider、`workbuddy-xdpool` 设置节、各条同源路由(状态 / 重新检测 / 清除冷却 / 签到 / 自动化运行 / 保留积分),以及账号发现与模型目录播种。
|
|
187
|
+
- `accounts.ts` —— `WorkBuddyAccountPool`:读本机 WorkBuddy 桌面 auth 快照、429 冷却、轮换与 token 刷新;账号停用与积分保留也在这里。
|
|
188
|
+
- `scheduler.ts` —— 积分自动化的调度器:按本地时点跑五个任务(签到 / 上报 / 任务 / 连登 / 旅行),每日收益账本落盘,手动「立即运行」走的是同一套逻辑。
|
|
189
|
+
- `task-events.ts` —— 13 条任务事件链的构造。每条链都是纯数据,外加它该走哪个指纹通道(桌面 / 网页);需要真实会话的任务(技能、专家)在这里先开一次真对话,拿到服务端 id。
|
|
190
|
+
- `catalog.ts` / `upstream.ts` —— 上游模型目录(含每模型积分倍率、免费 / 图片能力标签)、积分查询、签到、自动化各接口的上游客户端(按凭据域名自动切国内外)。
|
|
191
|
+
- `web-status.ts` / `status-paths.ts` —— 卡片读的同源状态文档与路由。写操作按「POST + 回环来源 + 显式 accountId」把关。
|
|
192
|
+
- `bin.ts` —— 上面那套 CLI。
|
|
193
|
+
- **客户端**(`src/client/`,浏览器卡片,经 `dsh.client` 由宿主加载)
|
|
194
|
+
折叠卡片外壳沿用宿主内置卡的 `dsm-plugin-card*` 样式语言(`--dsw-alias-*` 主题变量),内容类名统一 `dsm-workbuddy-xdpool-*` 前缀,不污染宿主其它卡片;文案命名空间 `settings.workbuddy-xdpool`。
|
|
195
|
+
- **构建**
|
|
196
|
+
`tsdown` 产出 `lib/index.js`(宿主入口)+ `lib/index.d.ts`(类型)+ `lib/bin.js`(CLI)+ `lib/client.js`(CJS,用 `window.__ModuleLoader__.load` 包起来的浏览器 bundle)。四个产物都随仓库提交,所以安装时不需要任何构建脚本。
|
|
155
197
|
|
|
156
198
|
## 已知限制
|
|
157
199
|
|
|
158
|
-
-
|
|
159
|
-
|
|
160
|
-
-
|
|
200
|
+
- **只能用本机桌面 App 里的账号**:池不会、也没法替你发起 WorkBuddy 的登录或扫码(token 由 WorkBuddy 桌面 App 自己的腾讯 SSO 铸造并和设备绑定)。加号 = 在桌面 App 里登录 / 切换,XD Pool 自动吸收。
|
|
201
|
+
|
|
202
|
+
- **自动化里有几个任务刻意没做**
|
|
203
|
+
- `Expert_Philanthropy`(公益专家):需要真捐钱,绕不过去。
|
|
204
|
+
- `black_cat`(夜猫子):只在 23:00–08:00 计分,而且**没有积分奖励**——熬夜白熬。
|
|
205
|
+
- `Model_chat_GLM5.2`(指定模型对话)与 `wb_wechat_oa_subscribe_task`(关注公众号):路径已经摸清,留到下个版本。
|
|
206
|
+
|
|
207
|
+
- **`Expert_team_use_3` 偶发卡在 2/3**:有个号当天用掉两次专家团后,第三次怎么发都不涨(换个没用过的专家团也不涨)。怀疑该任务对单账号有当日额度、跨天恢复,但没验证。**新号不受影响**(实测 0/3 → 3/3)。
|
|
208
|
+
|
|
209
|
+
- **依赖 WorkBuddy 客户端接口**(不是官方开放 API),WorkBuddy 更新后插件可能得跟着调。某个账号的 refresh token 失效时,回桌面重新登录即可。
|
|
210
|
+
|
|
211
|
+
- 如果 Windows 和 Linux 用户名不同、且 Windows 环境变量没传进 WSL,请用 `WORKBUDDY_AUTH_FILE` 或配置里的 `authFile` 指定实际位置。
|
|
161
212
|
|
|
162
213
|
## 免责声明
|
|
163
214
|
|
|
@@ -172,7 +223,7 @@ workbuddy-xdpool:
|
|
|
172
223
|
|
|
173
224
|
- [corrinehu/dsh-workbuddy-connect](https://github.com/corrinehu/dsh-workbuddy-connect)(MIT)—— 设置节注册(`settings.installSection`)与 DSH 插件结构、客户端卡片加载机制、桌面端凭据刷新与 loopback shim 加固的核心参照;本项目沿用其「宿主通过 installSection 挂卡片」的打通路径。
|
|
174
225
|
- [dingminhua/dsh-connect-workbuddy](https://github.com/dingminhua/dsh-connect-workbuddy)(MIT,Copyright (c) 2026 LaoDing)—— `dsm-plugin-card*` 卡片样式语言与 `--dsw-alias-*` 主题变量的参照实现;**每日签到**(`/v2/billing/meter/checkin-activity-status` 与 `/v2/billing/meter/daily-checkin`)、积分包聚合口径(月度周期套餐 / 一次性礼包区分)与国内 / 国际版按 `domain` 选择上游域名的做法,参考了该项目已验证的接口形态。
|
|
175
|
-
- [Sliverkiss/workbuddy2api](https://github.com/Sliverkiss/workbuddy2api)(MIT)—— WorkBuddy 上游协议(`copilot.tencent.com` 的 wire behavior
|
|
226
|
+
- [Sliverkiss/workbuddy2api](https://github.com/Sliverkiss/workbuddy2api)(MIT)—— WorkBuddy 上游协议(`copilot.tencent.com` 的 wire behavior)与积分接口的参照实现;**积分自动化**(成长中心签到 / 活跃上报 / 连登兑换 / 猫猫旅行状态机 / 13 条任务事件链 / 专家召唤链)整体照该项目的 Go 版逆向实现移植,每条事件链的判据与实测结论都来自它。
|
|
176
227
|
|
|
177
228
|
以上项目的版权归各自作者所有。本项目采用**参考设计思路 + 独立实现**的方式,未整体复制任何参考项目的源码。若标注有遗漏或不当之处,欢迎提交 issue 指正。
|
|
178
229
|
|
|
Binary file
|
package/assets/settings-card.png
CHANGED
|
Binary file
|
package/lib/bin.js
CHANGED
|
@@ -2714,6 +2714,16 @@ function dayKey(date) {
|
|
|
2714
2714
|
return `${date.getFullYear()}-${month}-${day}`;
|
|
2715
2715
|
}
|
|
2716
2716
|
/**
|
|
2717
|
+
* The scheduled SLOT `date` falls in, as `YYYY-MM-DDTHH`.
|
|
2718
|
+
*
|
|
2719
|
+
* The per-job run guard keys on this instead of the date, so a job configured
|
|
2720
|
+
* for several hours runs in each of them while a second tick inside the same
|
|
2721
|
+
* hour is still refused.
|
|
2722
|
+
*/
|
|
2723
|
+
function slotKey(date) {
|
|
2724
|
+
return `${dayKey(date)}T${String(date.getHours()).padStart(2, "0")}`;
|
|
2725
|
+
}
|
|
2726
|
+
/**
|
|
2717
2727
|
* Whether `now`'s local hour is one of `hours`.
|
|
2718
2728
|
*
|
|
2719
2729
|
* The reference panel computes a `nextFire` instant and sleeps until it; this
|
|
@@ -2818,7 +2828,7 @@ var WorkBuddyScheduler = class {
|
|
|
2818
2828
|
this.reportHours = options.reportHours ?? [10];
|
|
2819
2829
|
this.taskHours = options.taskHours ?? [11];
|
|
2820
2830
|
this.streakHours = options.streakHours ?? [12];
|
|
2821
|
-
this.travelHours = options.travelHours ?? [
|
|
2831
|
+
this.travelHours = options.travelHours ?? [9, 21];
|
|
2822
2832
|
}
|
|
2823
2833
|
/** Apply a new configuration; safe to call while running. */
|
|
2824
2834
|
/**
|
|
@@ -2896,7 +2906,7 @@ var WorkBuddyScheduler = class {
|
|
|
2896
2906
|
async runNow(kind, force = false) {
|
|
2897
2907
|
const today = dayKey(this.now());
|
|
2898
2908
|
const state = this.states[kind];
|
|
2899
|
-
if (!force && state.
|
|
2909
|
+
if (!force && state.lastRunSlot === slotKey(this.now())) return { ...state };
|
|
2900
2910
|
this.busy = true;
|
|
2901
2911
|
try {
|
|
2902
2912
|
await this.runJob(kind, today);
|
|
@@ -2991,10 +3001,11 @@ var WorkBuddyScheduler = class {
|
|
|
2991
3001
|
this.busy = true;
|
|
2992
3002
|
try {
|
|
2993
3003
|
const now = this.now();
|
|
3004
|
+
const slot = slotKey(now);
|
|
2994
3005
|
const today = dayKey(now);
|
|
2995
3006
|
for (const kind of JOB_KINDS) {
|
|
2996
3007
|
if (this.stopped) return;
|
|
2997
|
-
if (this.states[kind].
|
|
3008
|
+
if (this.states[kind].lastRunSlot === slot) continue;
|
|
2998
3009
|
if (!isFireHour(now, this.hoursOf(kind))) continue;
|
|
2999
3010
|
await this.runJob(kind, today);
|
|
3000
3011
|
}
|
|
@@ -3092,6 +3103,8 @@ var WorkBuddyScheduler = class {
|
|
|
3092
3103
|
let credit = 0;
|
|
3093
3104
|
let energy = 0;
|
|
3094
3105
|
let claimed = 0;
|
|
3106
|
+
const detail = [];
|
|
3107
|
+
let progressNote;
|
|
3095
3108
|
const accounts = this.accountsInOrder();
|
|
3096
3109
|
if (kind === "tasks") await this.sendEventChains(accounts);
|
|
3097
3110
|
for (let index = 0; index < accounts.length; index++) {
|
|
@@ -3104,7 +3117,10 @@ var WorkBuddyScheduler = class {
|
|
|
3104
3117
|
try {
|
|
3105
3118
|
const claim = await this.client.claimDailyCheckin(account.credential);
|
|
3106
3119
|
this.recordEarnings(account.id, today, { checkinCredit: claim.credit });
|
|
3107
|
-
if (claim.credit > 0)
|
|
3120
|
+
if (claim.credit > 0) {
|
|
3121
|
+
if (claim.credit > 0) detail.push(`签到 +${claim.credit}`);
|
|
3122
|
+
this.logger.info?.(`automation checkin ${account.label}: +${claim.credit} credit`);
|
|
3123
|
+
}
|
|
3108
3124
|
} catch (error) {
|
|
3109
3125
|
if (!isAlreadyCheckin(error)) throw error;
|
|
3110
3126
|
this.logger.info?.(`automation checkin ${account.label}: already done today`);
|
|
@@ -3120,6 +3136,7 @@ var WorkBuddyScheduler = class {
|
|
|
3120
3136
|
credit += result.credit;
|
|
3121
3137
|
energy += result.energy;
|
|
3122
3138
|
claimed += result.claimed;
|
|
3139
|
+
detail.push(...result.titles);
|
|
3123
3140
|
this.claimableSeen += result.claimableCount;
|
|
3124
3141
|
this.recordEarnings(account.id, today, {
|
|
3125
3142
|
credit: result.credit,
|
|
@@ -3129,9 +3146,11 @@ var WorkBuddyScheduler = class {
|
|
|
3129
3146
|
this.logger.info?.(`automation tasks ${account.label}: ${result.claimed} claimed (+${result.credit} credit, +${result.energy} energy, ${result.claimableCount} claimable seen)`);
|
|
3130
3147
|
break;
|
|
3131
3148
|
}
|
|
3132
|
-
case "streak":
|
|
3133
|
-
await this.redeemStreak(account);
|
|
3149
|
+
case "streak": {
|
|
3150
|
+
const progress = await this.redeemStreak(account);
|
|
3151
|
+
if (progress !== void 0) progressNote = progress;
|
|
3134
3152
|
break;
|
|
3153
|
+
}
|
|
3135
3154
|
case "travel": await this.runTravel(account);
|
|
3136
3155
|
}
|
|
3137
3156
|
ok++;
|
|
@@ -3142,6 +3161,7 @@ var WorkBuddyScheduler = class {
|
|
|
3142
3161
|
if (index < accounts.length - 1 && this.delayMs > 0 && !this.stopped) await sleep(this.delayMs);
|
|
3143
3162
|
}
|
|
3144
3163
|
const state = this.states[kind];
|
|
3164
|
+
state.lastRunSlot = slotKey(this.now());
|
|
3145
3165
|
state.lastRunDate = today;
|
|
3146
3166
|
state.lastRunAtMs = this.now().getTime();
|
|
3147
3167
|
state.ok = ok;
|
|
@@ -3150,6 +3170,8 @@ var WorkBuddyScheduler = class {
|
|
|
3150
3170
|
state.energy = energy;
|
|
3151
3171
|
state.claimed = claimed;
|
|
3152
3172
|
state.message = this.summarise(kind, ok, failed, claimed, credit, energy);
|
|
3173
|
+
state.detail = detail;
|
|
3174
|
+
state.progress = progressNote;
|
|
3153
3175
|
this.logger.info?.(`automation ${accountWord}: ${state.message}`);
|
|
3154
3176
|
}
|
|
3155
3177
|
/** Compose the one-line summary shown on the card. */
|
|
@@ -3352,6 +3374,7 @@ var WorkBuddyScheduler = class {
|
|
|
3352
3374
|
let credit = 0;
|
|
3353
3375
|
let energy = 0;
|
|
3354
3376
|
let claimed = 0;
|
|
3377
|
+
const titles = [];
|
|
3355
3378
|
for (const task of claimable) {
|
|
3356
3379
|
if (this.stopped) break;
|
|
3357
3380
|
const reward = await this.client.claimTaskReward(credential, task.taskCode);
|
|
@@ -3359,6 +3382,7 @@ var WorkBuddyScheduler = class {
|
|
|
3359
3382
|
energy += reward.energy;
|
|
3360
3383
|
if (reward.credit > 0 || reward.energy > 0) {
|
|
3361
3384
|
claimed++;
|
|
3385
|
+
titles.push(task.title);
|
|
3362
3386
|
this.logger.info?.(`automation claim ${account.label}: ${task.title} +${reward.credit}c +${reward.energy}e`);
|
|
3363
3387
|
} else this.logger.info?.(`automation claim ${account.label}: ${task.taskCode} already claimed`);
|
|
3364
3388
|
if (this.delayMs > 0 && !this.stopped) await sleep(this.delayMs);
|
|
@@ -3367,7 +3391,8 @@ var WorkBuddyScheduler = class {
|
|
|
3367
3391
|
claimed,
|
|
3368
3392
|
credit,
|
|
3369
3393
|
energy,
|
|
3370
|
-
claimableCount: claimable.length
|
|
3394
|
+
claimableCount: claimable.length,
|
|
3395
|
+
titles
|
|
3371
3396
|
};
|
|
3372
3397
|
}
|
|
3373
3398
|
/**
|
|
@@ -3407,6 +3432,11 @@ var WorkBuddyScheduler = class {
|
|
|
3407
3432
|
}
|
|
3408
3433
|
if (this.delayMs > 0 && !this.stopped) await sleep(this.delayMs);
|
|
3409
3434
|
}
|
|
3435
|
+
const pendingTier = status.tiers.find((tier) => tier.status === "locked");
|
|
3436
|
+
if (pendingTier !== void 0) {
|
|
3437
|
+
const remaining = Math.max(0, pendingTier.days - status.days);
|
|
3438
|
+
return remaining > 0 ? `${pendingTier.tier} in ${remaining}d` : `${pendingTier.tier} ready`;
|
|
3439
|
+
}
|
|
3410
3440
|
}
|
|
3411
3441
|
/**
|
|
3412
3442
|
* One trip through the buddy travel loop for an account.
|
package/lib/client.js
CHANGED
|
@@ -275,6 +275,10 @@ window.__ModuleLoader__.load({
|
|
|
275
275
|
.dsm-workbuddy-xdpool-auto-job-name{flex:0 0 72px;color:var(--dsw-alias-label-primary,#e8e8ea)}
|
|
276
276
|
.dsm-workbuddy-xdpool-auto-job-when{flex:1 1 auto;font-variant-numeric:tabular-nums}
|
|
277
277
|
.dsm-workbuddy-xdpool-auto-job-last{flex:0 0 auto;text-align:right;font-variant-numeric:tabular-nums}
|
|
278
|
+
/* The job detail wraps to its own full-width line: it is a list of reward
|
|
279
|
+
titles, which needs the whole row rather than a cramped right-hand slot. */
|
|
280
|
+
.dsm-workbuddy-xdpool-auto-job-detail{flex:1 1 100%;color:var(--dsw-alias-label-secondary,#b8bcc4);line-height:1.5;word-break:break-word}
|
|
281
|
+
.dsm-workbuddy-xdpool-auto-job-note{flex:0 0 auto;color:var(--dsw-alias-label-secondary,#b8bcc4)}
|
|
278
282
|
.dsm-workbuddy-xdpool-auto-run{flex:0 0 auto;padding:2px 8px;font-size:10px;line-height:16px}
|
|
279
283
|
/* Reserved credits: one inline number field per account. */
|
|
280
284
|
.dsm-workbuddy-xdpool-reserve{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:8px;padding-top:8px;border-top:1px dashed var(--dsw-alias-border-l2,#36373b);font-size:11px;color:var(--dsw-alias-label-dimmed,#8a97b5)}
|
|
@@ -362,10 +366,11 @@ window.__ModuleLoader__.load({
|
|
|
362
366
|
const AUTOMATION_POLL_MS = 2e3;
|
|
363
367
|
const AUTOMATION_POLL_ATTEMPTS = 90;
|
|
364
368
|
const AUTOMATION_JOBS = [
|
|
369
|
+
"checkin",
|
|
365
370
|
"report",
|
|
366
371
|
"tasks",
|
|
367
|
-
"
|
|
368
|
-
"
|
|
372
|
+
"streak",
|
|
373
|
+
"travel"
|
|
369
374
|
];
|
|
370
375
|
/** Read one job's configured hours off the status document. */
|
|
371
376
|
function automationHours(status, kind) {
|
|
@@ -376,6 +381,7 @@ window.__ModuleLoader__.load({
|
|
|
376
381
|
case "tasks": return automation.taskHours;
|
|
377
382
|
case "checkin": return automation.checkinHours;
|
|
378
383
|
case "streak": return automation.streakHours;
|
|
384
|
+
case "travel": return automation.travelHours;
|
|
379
385
|
}
|
|
380
386
|
}
|
|
381
387
|
/** Read one job's last-run record off the status document. */
|
|
@@ -1132,6 +1138,14 @@ window.__ModuleLoader__.load({
|
|
|
1132
1138
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1133
1139
|
className: "dsm-workbuddy-xdpool-auto-job-last",
|
|
1134
1140
|
children: job?.lastRunDate === void 0 ? t?.("row.autoNever") ?? "not run yet" : `${job.lastRunDate} · ${job.ok}${job.failed > 0 ? `/${job.failed}` : ""}`
|
|
1141
|
+
}),
|
|
1142
|
+
job?.progress === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1143
|
+
className: "dsm-workbuddy-xdpool-auto-job-note",
|
|
1144
|
+
children: job.progress
|
|
1145
|
+
}),
|
|
1146
|
+
job?.detail === void 0 || job.detail.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1147
|
+
className: "dsm-workbuddy-xdpool-auto-job-detail",
|
|
1148
|
+
children: job.detail.join(" · ")
|
|
1135
1149
|
})
|
|
1136
1150
|
]
|
|
1137
1151
|
}, kind);
|
|
@@ -1767,13 +1781,14 @@ window.__ModuleLoader__.load({
|
|
|
1767
1781
|
"row.autoOn": "On",
|
|
1768
1782
|
"row.autoOff": "Off",
|
|
1769
1783
|
"row.autoBusy": "Saving…",
|
|
1770
|
-
"row.autoHintOn": "
|
|
1784
|
+
"row.autoHintOn": "Checks in, reports activity, claims task and streak rewards, and runs the buddy trip — every day.",
|
|
1771
1785
|
"row.autoHintOff": "Off: no background requests are made for you.",
|
|
1772
1786
|
"row.autoJob_report": "Activity report",
|
|
1773
1787
|
"row.autoJob_tasks": "Task rewards",
|
|
1774
1788
|
"row.autoJob_checkin": "Daily check-in",
|
|
1775
1789
|
"row.autoJob_streak": "Streak bonus",
|
|
1776
|
-
"row.
|
|
1790
|
+
"row.autoJob_travel": "Buddy trip",
|
|
1791
|
+
"row.autoHourNone": "skipped today",
|
|
1777
1792
|
"row.autoNever": "not run yet",
|
|
1778
1793
|
"row.autoRun": "Run now",
|
|
1779
1794
|
"row.autoRunning": "Running…",
|
|
@@ -1895,14 +1910,15 @@ window.__ModuleLoader__.load({
|
|
|
1895
1910
|
"row.autoOn": "已开启",
|
|
1896
1911
|
"row.autoOff": "已关闭",
|
|
1897
1912
|
"row.autoBusy": "保存中…",
|
|
1898
|
-
"row.autoHintOn": "
|
|
1913
|
+
"row.autoHintOn": "每天自动签到、上报活跃、领取任务奖励与连登奖励,并照看猫猫旅行。",
|
|
1899
1914
|
"row.autoHintOff": "已关闭:不会替你发起任何后台请求。",
|
|
1900
1915
|
"row.autoJob_report": "活跃上报",
|
|
1901
1916
|
"row.autoJob_tasks": "任务奖励",
|
|
1902
1917
|
"row.autoJob_checkin": "每日签到",
|
|
1903
1918
|
"row.autoJob_streak": "连登奖励",
|
|
1904
|
-
"row.
|
|
1905
|
-
"row.
|
|
1919
|
+
"row.autoJob_travel": "猫猫旅行",
|
|
1920
|
+
"row.autoHourNone": "当天不跑",
|
|
1921
|
+
"row.autoNever": "还没跑过",
|
|
1906
1922
|
"row.autoRun": "立即运行",
|
|
1907
1923
|
"row.autoRunning": "运行中…",
|
|
1908
1924
|
"row.autoRan": "完成:{count} 个账号正常,{failed} 个失败",
|
package/lib/index.d.ts
CHANGED
|
@@ -1151,6 +1151,16 @@ interface SchedulerLogger {
|
|
|
1151
1151
|
interface AutomationJobState {
|
|
1152
1152
|
/** `YYYY-MM-DD` of the last completed run, or undefined if it never ran. */
|
|
1153
1153
|
lastRunDate?: string;
|
|
1154
|
+
/**
|
|
1155
|
+
* The scheduled SLOT of the last run, as `YYYY-MM-DDTHH`.
|
|
1156
|
+
*
|
|
1157
|
+
* The tick de-duplicates on this rather than on the date: keying on the date
|
|
1158
|
+
* alone caps every job at one run a day, which is wrong for a job with two
|
|
1159
|
+
* time points — blocking the cat loop's second pass would leave the cat out
|
|
1160
|
+
* until tomorrow. Per slot a job runs once in each configured hour, while a
|
|
1161
|
+
* repeat tick inside the same hour is still refused.
|
|
1162
|
+
*/
|
|
1163
|
+
lastRunSlot?: string;
|
|
1154
1164
|
/** Epoch ms of the last completed run. */
|
|
1155
1165
|
lastRunAtMs?: number;
|
|
1156
1166
|
/** Accounts that completed without throwing. */
|
|
@@ -1164,6 +1174,23 @@ interface AutomationJobState {
|
|
|
1164
1174
|
/** Tasks claimed by the task job on the last run. */
|
|
1165
1175
|
claimed: number;
|
|
1166
1176
|
/** Human-readable summary of the last run. */
|
|
1177
|
+
/**
|
|
1178
|
+
* What this run actually did, in the words of the task board.
|
|
1179
|
+
*
|
|
1180
|
+
* `message` is a count ("3 accounts, 5 tasks claimed"); this is the list a
|
|
1181
|
+
* person can check off — the reward titles the pass collected. A row showing
|
|
1182
|
+
* only a bare number cannot answer "did it do the thing I care about", which
|
|
1183
|
+
* is the question the panel exists to answer.
|
|
1184
|
+
*/
|
|
1185
|
+
detail?: readonly string[];
|
|
1186
|
+
/**
|
|
1187
|
+
* A pending milestone worth naming, when there is one.
|
|
1188
|
+
*
|
|
1189
|
+
* Streak tiers are why this exists: every tier reads `locked` until enough
|
|
1190
|
+
* consecutive days accumulate, and "locked" on its own reads as "broken"
|
|
1191
|
+
* rather than "come back in four days".
|
|
1192
|
+
*/
|
|
1193
|
+
progress?: string;
|
|
1167
1194
|
message?: string;
|
|
1168
1195
|
}
|
|
1169
1196
|
/**
|
|
@@ -1794,6 +1821,15 @@ interface PoolWebAutomationJob {
|
|
|
1794
1821
|
claimed: number;
|
|
1795
1822
|
/** One-line summary of the last run. */
|
|
1796
1823
|
message?: string;
|
|
1824
|
+
/**
|
|
1825
|
+
* What the last run actually did, in the words of the task board.
|
|
1826
|
+
*
|
|
1827
|
+
* `message` is a count; this is the list a person can check off, which is
|
|
1828
|
+
* what turns a row from "it ran" into "it did the things I care about".
|
|
1829
|
+
*/
|
|
1830
|
+
detail?: readonly string[];
|
|
1831
|
+
/** A pending milestone worth naming, e.g. the next streak tier countdown. */
|
|
1832
|
+
progress?: string;
|
|
1797
1833
|
}
|
|
1798
1834
|
/**
|
|
1799
1835
|
* Automation block on the status document.
|
|
@@ -1812,6 +1848,7 @@ interface PoolWebAutomation {
|
|
|
1812
1848
|
reportHours: readonly number[];
|
|
1813
1849
|
taskHours: readonly number[];
|
|
1814
1850
|
streakHours: readonly number[];
|
|
1851
|
+
travelHours: readonly number[];
|
|
1815
1852
|
jobs: {
|
|
1816
1853
|
checkin: PoolWebAutomationJob;
|
|
1817
1854
|
report: PoolWebAutomationJob;
|
package/lib/index.js
CHANGED
|
@@ -3031,6 +3031,16 @@ function dayKey(date) {
|
|
|
3031
3031
|
return `${date.getFullYear()}-${month}-${day}`;
|
|
3032
3032
|
}
|
|
3033
3033
|
/**
|
|
3034
|
+
* The scheduled SLOT `date` falls in, as `YYYY-MM-DDTHH`.
|
|
3035
|
+
*
|
|
3036
|
+
* The per-job run guard keys on this instead of the date, so a job configured
|
|
3037
|
+
* for several hours runs in each of them while a second tick inside the same
|
|
3038
|
+
* hour is still refused.
|
|
3039
|
+
*/
|
|
3040
|
+
function slotKey(date) {
|
|
3041
|
+
return `${dayKey(date)}T${String(date.getHours()).padStart(2, "0")}`;
|
|
3042
|
+
}
|
|
3043
|
+
/**
|
|
3034
3044
|
* Whether `now`'s local hour is one of `hours`.
|
|
3035
3045
|
*
|
|
3036
3046
|
* The reference panel computes a `nextFire` instant and sleeps until it; this
|
|
@@ -3135,7 +3145,7 @@ var WorkBuddyScheduler = class {
|
|
|
3135
3145
|
this.reportHours = options.reportHours ?? [10];
|
|
3136
3146
|
this.taskHours = options.taskHours ?? [11];
|
|
3137
3147
|
this.streakHours = options.streakHours ?? [12];
|
|
3138
|
-
this.travelHours = options.travelHours ?? [
|
|
3148
|
+
this.travelHours = options.travelHours ?? [9, 21];
|
|
3139
3149
|
}
|
|
3140
3150
|
/** Apply a new configuration; safe to call while running. */
|
|
3141
3151
|
/**
|
|
@@ -3213,7 +3223,7 @@ var WorkBuddyScheduler = class {
|
|
|
3213
3223
|
async runNow(kind, force = false) {
|
|
3214
3224
|
const today = dayKey(this.now());
|
|
3215
3225
|
const state = this.states[kind];
|
|
3216
|
-
if (!force && state.
|
|
3226
|
+
if (!force && state.lastRunSlot === slotKey(this.now())) return { ...state };
|
|
3217
3227
|
this.busy = true;
|
|
3218
3228
|
try {
|
|
3219
3229
|
await this.runJob(kind, today);
|
|
@@ -3308,10 +3318,11 @@ var WorkBuddyScheduler = class {
|
|
|
3308
3318
|
this.busy = true;
|
|
3309
3319
|
try {
|
|
3310
3320
|
const now = this.now();
|
|
3321
|
+
const slot = slotKey(now);
|
|
3311
3322
|
const today = dayKey(now);
|
|
3312
3323
|
for (const kind of JOB_KINDS) {
|
|
3313
3324
|
if (this.stopped) return;
|
|
3314
|
-
if (this.states[kind].
|
|
3325
|
+
if (this.states[kind].lastRunSlot === slot) continue;
|
|
3315
3326
|
if (!isFireHour(now, this.hoursOf(kind))) continue;
|
|
3316
3327
|
await this.runJob(kind, today);
|
|
3317
3328
|
}
|
|
@@ -3409,6 +3420,8 @@ var WorkBuddyScheduler = class {
|
|
|
3409
3420
|
let credit = 0;
|
|
3410
3421
|
let energy = 0;
|
|
3411
3422
|
let claimed = 0;
|
|
3423
|
+
const detail = [];
|
|
3424
|
+
let progressNote;
|
|
3412
3425
|
const accounts = this.accountsInOrder();
|
|
3413
3426
|
if (kind === "tasks") await this.sendEventChains(accounts);
|
|
3414
3427
|
for (let index = 0; index < accounts.length; index++) {
|
|
@@ -3421,7 +3434,10 @@ var WorkBuddyScheduler = class {
|
|
|
3421
3434
|
try {
|
|
3422
3435
|
const claim = await this.client.claimDailyCheckin(account.credential);
|
|
3423
3436
|
this.recordEarnings(account.id, today, { checkinCredit: claim.credit });
|
|
3424
|
-
if (claim.credit > 0)
|
|
3437
|
+
if (claim.credit > 0) {
|
|
3438
|
+
if (claim.credit > 0) detail.push(`签到 +${claim.credit}`);
|
|
3439
|
+
this.logger.info?.(`automation checkin ${account.label}: +${claim.credit} credit`);
|
|
3440
|
+
}
|
|
3425
3441
|
} catch (error) {
|
|
3426
3442
|
if (!isAlreadyCheckin(error)) throw error;
|
|
3427
3443
|
this.logger.info?.(`automation checkin ${account.label}: already done today`);
|
|
@@ -3437,6 +3453,7 @@ var WorkBuddyScheduler = class {
|
|
|
3437
3453
|
credit += result.credit;
|
|
3438
3454
|
energy += result.energy;
|
|
3439
3455
|
claimed += result.claimed;
|
|
3456
|
+
detail.push(...result.titles);
|
|
3440
3457
|
this.claimableSeen += result.claimableCount;
|
|
3441
3458
|
this.recordEarnings(account.id, today, {
|
|
3442
3459
|
credit: result.credit,
|
|
@@ -3446,9 +3463,11 @@ var WorkBuddyScheduler = class {
|
|
|
3446
3463
|
this.logger.info?.(`automation tasks ${account.label}: ${result.claimed} claimed (+${result.credit} credit, +${result.energy} energy, ${result.claimableCount} claimable seen)`);
|
|
3447
3464
|
break;
|
|
3448
3465
|
}
|
|
3449
|
-
case "streak":
|
|
3450
|
-
await this.redeemStreak(account);
|
|
3466
|
+
case "streak": {
|
|
3467
|
+
const progress = await this.redeemStreak(account);
|
|
3468
|
+
if (progress !== void 0) progressNote = progress;
|
|
3451
3469
|
break;
|
|
3470
|
+
}
|
|
3452
3471
|
case "travel": await this.runTravel(account);
|
|
3453
3472
|
}
|
|
3454
3473
|
ok++;
|
|
@@ -3459,6 +3478,7 @@ var WorkBuddyScheduler = class {
|
|
|
3459
3478
|
if (index < accounts.length - 1 && this.delayMs > 0 && !this.stopped) await sleep(this.delayMs);
|
|
3460
3479
|
}
|
|
3461
3480
|
const state = this.states[kind];
|
|
3481
|
+
state.lastRunSlot = slotKey(this.now());
|
|
3462
3482
|
state.lastRunDate = today;
|
|
3463
3483
|
state.lastRunAtMs = this.now().getTime();
|
|
3464
3484
|
state.ok = ok;
|
|
@@ -3467,6 +3487,8 @@ var WorkBuddyScheduler = class {
|
|
|
3467
3487
|
state.energy = energy;
|
|
3468
3488
|
state.claimed = claimed;
|
|
3469
3489
|
state.message = this.summarise(kind, ok, failed, claimed, credit, energy);
|
|
3490
|
+
state.detail = detail;
|
|
3491
|
+
state.progress = progressNote;
|
|
3470
3492
|
this.logger.info?.(`automation ${accountWord}: ${state.message}`);
|
|
3471
3493
|
}
|
|
3472
3494
|
/** Compose the one-line summary shown on the card. */
|
|
@@ -3669,6 +3691,7 @@ var WorkBuddyScheduler = class {
|
|
|
3669
3691
|
let credit = 0;
|
|
3670
3692
|
let energy = 0;
|
|
3671
3693
|
let claimed = 0;
|
|
3694
|
+
const titles = [];
|
|
3672
3695
|
for (const task of claimable) {
|
|
3673
3696
|
if (this.stopped) break;
|
|
3674
3697
|
const reward = await this.client.claimTaskReward(credential, task.taskCode);
|
|
@@ -3676,6 +3699,7 @@ var WorkBuddyScheduler = class {
|
|
|
3676
3699
|
energy += reward.energy;
|
|
3677
3700
|
if (reward.credit > 0 || reward.energy > 0) {
|
|
3678
3701
|
claimed++;
|
|
3702
|
+
titles.push(task.title);
|
|
3679
3703
|
this.logger.info?.(`automation claim ${account.label}: ${task.title} +${reward.credit}c +${reward.energy}e`);
|
|
3680
3704
|
} else this.logger.info?.(`automation claim ${account.label}: ${task.taskCode} already claimed`);
|
|
3681
3705
|
if (this.delayMs > 0 && !this.stopped) await sleep(this.delayMs);
|
|
@@ -3684,7 +3708,8 @@ var WorkBuddyScheduler = class {
|
|
|
3684
3708
|
claimed,
|
|
3685
3709
|
credit,
|
|
3686
3710
|
energy,
|
|
3687
|
-
claimableCount: claimable.length
|
|
3711
|
+
claimableCount: claimable.length,
|
|
3712
|
+
titles
|
|
3688
3713
|
};
|
|
3689
3714
|
}
|
|
3690
3715
|
/**
|
|
@@ -3724,6 +3749,11 @@ var WorkBuddyScheduler = class {
|
|
|
3724
3749
|
}
|
|
3725
3750
|
if (this.delayMs > 0 && !this.stopped) await sleep(this.delayMs);
|
|
3726
3751
|
}
|
|
3752
|
+
const pendingTier = status.tiers.find((tier) => tier.status === "locked");
|
|
3753
|
+
if (pendingTier !== void 0) {
|
|
3754
|
+
const remaining = Math.max(0, pendingTier.days - status.days);
|
|
3755
|
+
return remaining > 0 ? `${pendingTier.tier} in ${remaining}d` : `${pendingTier.tier} ready`;
|
|
3756
|
+
}
|
|
3727
3757
|
}
|
|
3728
3758
|
/**
|
|
3729
3759
|
* One trip through the buddy travel loop for an account.
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "dsh-workbuddy-xdpool",
|
|
3
3
|
"displayName": "DSH WorkBuddy XD Pool",
|
|
4
4
|
"description": "Merge every locally signed-in WorkBuddy account into DeepSeek Harness as one auto-failing-over model pool (multi-account rotation, live credits, daily check-in and model catalog).",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.3.0",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "XDTrees",
|
|
8
8
|
"homepage": "https://github.com/XDTrees/dsh-workbuddy-xdpool#readme",
|