shuadouyin 0.3.0 → 0.3.2
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/.dy-build-commit +1 -1
- package/dist/app.js +29 -1
- package/dist/errors.js +3 -0
- package/dist/operations/reset.js +4 -0
- package/package.json +1 -1
- package/skills/dy/SKILL.md +37 -44
- package/skills/dy/references/setup.md +100 -0
package/.dy-build-commit
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
ab12c5892c78af42d44e52d70980c742fdd40484
|
package/dist/app.js
CHANGED
|
@@ -35,6 +35,7 @@ import { voiceMemories, voiceMemoryText } from "./operations/voice-memory.js";
|
|
|
35
35
|
import { write } from "./operations/write.js";
|
|
36
36
|
import { quiet } from "./progress.js";
|
|
37
37
|
import { Store } from "./store.js";
|
|
38
|
+
import { Workspaces } from "./workspace.js";
|
|
38
39
|
export { isWrite, resourceID, validate } from "./operations/validate.js";
|
|
39
40
|
// Commands that need the work itself in view, and are therefore blocked by the
|
|
40
41
|
// chat overlay. Reads only: a write states its own target and already fails
|
|
@@ -210,6 +211,10 @@ export class App {
|
|
|
210
211
|
const session = await this.chrome.connect(active, this.timeout, live ? "https://live.douyin.com" : undefined);
|
|
211
212
|
try {
|
|
212
213
|
const result = await this.read(session, operation, input, active);
|
|
214
|
+
// Every page answer carries the setup question until it is answered. It
|
|
215
|
+
// is attached here rather than deep inside each operation so no command
|
|
216
|
+
// has to remember, and so a command added later cannot forget.
|
|
217
|
+
const setup = await setupNotice(this.store.base);
|
|
213
218
|
if (operation === "chat.read" && this.store.bot_id) {
|
|
214
219
|
if (!result || typeof result !== "object")
|
|
215
220
|
throw new CliError("state_corrupt", "Chat read did not return a conversation window");
|
|
@@ -223,7 +228,7 @@ export class App {
|
|
|
223
228
|
}
|
|
224
229
|
if (!["status", "auth.status"].includes(operation))
|
|
225
230
|
await this.store.append(operation, result);
|
|
226
|
-
return result;
|
|
231
|
+
return setup && result && typeof result === "object" ? { ...result, setup } : result;
|
|
227
232
|
}
|
|
228
233
|
catch (error) {
|
|
229
234
|
// Cancellation is the caller's choice and its outcome is not a
|
|
@@ -695,6 +700,29 @@ async function waitForProfileWorks(session, signal) {
|
|
|
695
700
|
signal.throwIfAborted();
|
|
696
701
|
}
|
|
697
702
|
}
|
|
703
|
+
// The setup question, carried with the first answer instead of blocking it.
|
|
704
|
+
//
|
|
705
|
+
// A block was tried first and is wrong: someone who wants to look at a few videos
|
|
706
|
+
// before naming the bot would be stopped by an error, which is a worse experience
|
|
707
|
+
// than a nudge they can act on or ignore. A gate also has to decide which commands
|
|
708
|
+
// count, and every list like that is wrong at the edges.
|
|
709
|
+
//
|
|
710
|
+
// A notice rides along with whatever was asked for. The result the caller wanted is
|
|
711
|
+
// still there; the missing setup is stated once, in the same envelope, with the two
|
|
712
|
+
// questions to ask. It appears on every answer until the owner answers, because a
|
|
713
|
+
// notice that appears once is one a caller can miss.
|
|
714
|
+
export async function setupNotice(base) {
|
|
715
|
+
const state = await new Workspaces(base).onboarding().catch(() => null);
|
|
716
|
+
// `unknown` means the file is missing: a workspace that never ran init.
|
|
717
|
+
if (!state || state.status === "complete" || state.status === "skipped")
|
|
718
|
+
return null;
|
|
719
|
+
return {
|
|
720
|
+
status: state.status,
|
|
721
|
+
ask: ["What should this bot be called, and how should it sound?", "What must it never do?"],
|
|
722
|
+
next: "Save the persona with `dy workspace get AGENTS.md` for the revision, `dy workspace set AGENTS.md --text-file <file> --if-match <revision>`, then `dy onboarding complete`. If the owner would rather decide later, run `dy onboarding skip`.",
|
|
723
|
+
why: "Until this is answered the bot browses and comments as a generic assistant. Nothing in the output would say the owner was never asked.",
|
|
724
|
+
};
|
|
725
|
+
}
|
|
698
726
|
function publicBrowser(state) {
|
|
699
727
|
return { running: true, headless: state.headless, pid: state.pid, started_at: state.started_at };
|
|
700
728
|
}
|
package/dist/errors.js
CHANGED
|
@@ -35,6 +35,9 @@ function category(code) {
|
|
|
35
35
|
"already_exists",
|
|
36
36
|
"revision_required",
|
|
37
37
|
"revision_conflict",
|
|
38
|
+
// The bot has no persona yet. This is the installation's own state, not a
|
|
39
|
+
// failure of the command, and it is answered by asking the owner.
|
|
40
|
+
"setup_required",
|
|
38
41
|
"account_mismatch",
|
|
39
42
|
"migration_pending",
|
|
40
43
|
// A gate that refused because of the installation's own recorded
|
package/dist/operations/reset.js
CHANGED
|
@@ -15,6 +15,10 @@ const STATE = [
|
|
|
15
15
|
"MEMORY.md",
|
|
16
16
|
"history.jsonl",
|
|
17
17
|
"receipts.json",
|
|
18
|
+
// What earlier rounds learned. It was added after this list was written, so a
|
|
19
|
+
// reset kept it: a "fresh" bot started with everything the previous one had
|
|
20
|
+
// been taught, which is the opposite of starting over.
|
|
21
|
+
"lessons.md",
|
|
18
22
|
"growth.json",
|
|
19
23
|
"onboarding.json",
|
|
20
24
|
"state.sqlite",
|
package/package.json
CHANGED
package/skills/dy/SKILL.md
CHANGED
|
@@ -8,67 +8,47 @@ allowed-tools: Bash(dy:*) Bash(npx dy:*)
|
|
|
8
8
|
|
|
9
9
|
`dy` 是本地能力工具。当前 agent 负责理解、判断、对话、总结与调度。用 `dy schema` 查看可用命令;尊重用户当前授权和已有账号状态。
|
|
10
10
|
|
|
11
|
-
##
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
dy --version
|
|
15
|
-
```
|
|
11
|
+
## 第一次用:先问人设
|
|
16
12
|
|
|
17
|
-
|
|
13
|
+
新工作区里人格还是模板。这时候每个页面命令的返回里都会带一个 `setup` 字段:
|
|
18
14
|
|
|
19
|
-
```
|
|
20
|
-
|
|
15
|
+
```json
|
|
16
|
+
"setup": {
|
|
17
|
+
"status": "pending",
|
|
18
|
+
"ask": ["这个 bot 叫什么,说话什么调子?", "有什么事它绝对不能做?"],
|
|
19
|
+
"next": "…怎么保存人格…",
|
|
20
|
+
"why": "不回答的话,bot 会用通用助手的声音说话,而输出里没有任何东西会提示主人没被问过"
|
|
21
|
+
}
|
|
21
22
|
```
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
**命令照常执行**,`setup` 只是搭在结果上。看到它就先问主人这两个问题,别等主人自己想起来。
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
1. `dy workspace get AGENTS.md` 拿 revision
|
|
27
|
+
2. 改完 `dy workspace set AGENTS.md --text-file <file> --if-match <revision>`
|
|
28
|
+
3. `dy onboarding complete`
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
npm install -g github:9Ashwin/ShuaDouyin
|
|
29
|
-
```
|
|
30
|
+
主人说「以后再说」就跑 `dy onboarding skip`——跳过也是回答,之后不再提示。
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
npx skills add https://github.com/9Ashwin/ShuaDouyin --skill dy
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
或者用 CLI 自己装:
|
|
38
|
-
|
|
39
|
-
```bash
|
|
40
|
-
dy skill install
|
|
41
|
-
```
|
|
32
|
+
`setup` 只在新工作区出现。它没有拦你,是因为拦过一版:想先看几条视频再起名的人会被错误挡住,那比提示更糟。
|
|
42
33
|
|
|
43
|
-
|
|
34
|
+
## 先确认 dy 装好了
|
|
44
35
|
|
|
45
36
|
```bash
|
|
46
|
-
dy
|
|
37
|
+
dy --version
|
|
47
38
|
```
|
|
48
39
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
**判断新旧用 `behind`。** 版本号告诉你跨了几层功能,但一层里可能有几十个提交,所以只有 commit 能回答「我是不是最新的」。
|
|
52
|
-
|
|
53
|
-
按 `update` 字段给的命令更新。从 npm 装的:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
npm install -g shuadouyin@latest
|
|
57
|
-
```
|
|
40
|
+
有版本号就直接用。没有、或者要更新、要装 skill 到别的 agent 目录,读 `references/setup.md`——那里有安装、更新和各种安装形态的说明。
|
|
58
41
|
|
|
59
|
-
|
|
42
|
+
## 每次开始对话,先读人格
|
|
60
43
|
|
|
61
44
|
```bash
|
|
62
|
-
|
|
45
|
+
dy workspace get AGENTS.md
|
|
46
|
+
dy context show --query "<这一轮要做什么>"
|
|
63
47
|
```
|
|
64
48
|
|
|
65
|
-
|
|
49
|
+
**这不是可选的一步。** 那个文件第一行是 bot 的名字,`## 身份与声音` 里是它说话的样子。不读就用你自己默认的语气回答,那等于把主人设的人格扔了——而且从输出里看不出来是漏读了还是没照做。
|
|
66
50
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
npx skills add https://github.com/9Ashwin/ShuaDouyin --skill dy
|
|
71
|
-
```
|
|
51
|
+
读了之后,你的每一句话都用那个身份说,包括「我」的自称、句子的长短、有没有语气词。人格里写着「话多、爱笑、用短句和语气词」,而你回一段四平八稳的分析,那就是没照着做。
|
|
72
52
|
|
|
73
53
|
## 快速开始
|
|
74
54
|
|
|
@@ -207,6 +187,7 @@ dy guide # 这份文档的完整内容
|
|
|
207
187
|
|
|
208
188
|
| 你在做什么 | 读 |
|
|
209
189
|
| --- | --- |
|
|
190
|
+
| 安装、更新、卸载、磁盘占用 | `references/setup.md` |
|
|
210
191
|
| 不知道该用哪个命令 | `references/commands.md` |
|
|
211
192
|
| 浏览、观察、评论、私信、分享、发图 | `references/browse-and-grow.md` |
|
|
212
193
|
| 进直播间、发弹幕、送礼 | `references/live.md` |
|
|
@@ -250,7 +231,19 @@ dy guide # 这份文档的完整内容
|
|
|
250
231
|
|
|
251
232
|
## 用什么语气说话
|
|
252
233
|
|
|
253
|
-
`dy` 是在养一个 bot
|
|
234
|
+
`dy` 是在养一个 bot,不是跑一条流水线。语气来自 `AGENTS.md`,不是你自己的默认风格。
|
|
235
|
+
|
|
236
|
+
**人格写了什么,就照什么说。** 不是「参考一下」,是执行:
|
|
237
|
+
|
|
238
|
+
| 人格里写着 | 该有的样子 | 不该有的样子 |
|
|
239
|
+
| --- | --- | --- |
|
|
240
|
+
| 话多、爱笑、用语气词 | 「这条好好笑,评论区都在接梗欸」 | 「该视频评论区呈现互动特征」 |
|
|
241
|
+
| 沉稳、有观察力、先给事实 | 「三帧里两帧是字幕,中间那帧在讲结论」 | 「哇这个也太有意思了吧」 |
|
|
242
|
+
| 简洁、只说结论 | 「没发出去,按钮 0×0」 | 「经过排查,我发现了问题的根本原因在于……」 |
|
|
243
|
+
|
|
244
|
+
写完先看一眼:这句话换个 bot 也说得出来吗?说得出来,就说明人格没进去。
|
|
245
|
+
|
|
246
|
+
**名字用文件里的。** 第一行是「阿鱼」就别自称「猫猫」,改了名字也得先改文件。
|
|
254
247
|
|
|
255
248
|
**不要用交付工单的口吻。** 这些词一出现,人格就没了:
|
|
256
249
|
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# 安装与更新
|
|
2
|
+
|
|
3
|
+
只在需要的时候读这个文件。日常使用看 `SKILL.md`。
|
|
4
|
+
|
|
5
|
+
## 装 dy
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g shuadouyin
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
包叫 `shuadouyin`,命令叫 `dy`。发布包里带的是构建好的 `dist/`,装上就能跑,不需要本地编译。
|
|
12
|
+
|
|
13
|
+
**唯一需要的是本机已有的 Chrome**,不下载浏览器。
|
|
14
|
+
|
|
15
|
+
装完:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
dy init # 建工作区
|
|
19
|
+
dy auth login # 扫码登录抖音(有头 Chrome)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
从源码装也行,会构建一次,几秒:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g github:9Ashwin/ShuaDouyin
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
源码安装需要 `esbuild` 的平台二进制,而它是通过 esbuild 自己的安装脚本下载的。如果 npm 被配置成跳过生命周期脚本(本仓库的 `.npmrc` 就设了 `ignore-scripts`,有些人也是全局设的),安装会失败并提示 `Cannot find package 'esbuild'`。加 `--ignore-scripts=false` 重装即可。
|
|
29
|
+
|
|
30
|
+
## 装 skill 到 agent 目录
|
|
31
|
+
|
|
32
|
+
这样别的 agent 也能读到:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx skills add https://github.com/9Ashwin/ShuaDouyin --skill dy
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
或者用 CLI 自己装:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
dy skill install
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`dy skill status` 检查已装的副本和仓库是否一致。
|
|
45
|
+
|
|
46
|
+
## 更新
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
dy update --check
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
告诉你四件事:
|
|
53
|
+
|
|
54
|
+
- 这份是怎么装的(`checkout` / `npm-global` / `npm-local` / `managed-release`)
|
|
55
|
+
- 版本号
|
|
56
|
+
- 是哪个 commit 构建的
|
|
57
|
+
- 有没有更新的
|
|
58
|
+
|
|
59
|
+
**判断新旧用 `behind` 和 commit。** 版本号说明跨了几层功能,但一层里可能有几十个提交,所以只有 commit 能回答「我是不是最新的」。
|
|
60
|
+
|
|
61
|
+
按 `update` 字段给的命令更新。从 npm 装的:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
npm install -g shuadouyin@latest
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
从源码装的:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm install -g github:9Ashwin/ShuaDouyin@latest
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**从源码装的话,不加 `@latest` 或 `--force` 会显示 up to date 而不更新**——npm 记录的是 commit,不是分支,它认为已经满足要求了。npm 包按版本号,没这个问题。
|
|
74
|
+
|
|
75
|
+
更新完 skill 也要重装一次,否则 agent 读到的是旧说明:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx skills add https://github.com/9Ashwin/ShuaDouyin --skill dy
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 卸载
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
npm uninstall -g shuadouyin
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
卸载保留 `~/.dy` 里的 bot、记忆和账号登录状态。
|
|
88
|
+
|
|
89
|
+
要连状态一起清掉,手动删 `~/.dy`。删之前可以跑 `dy browser clean` 先回收缓存和截图——那部分通常占绝大部分空间,而登录和记忆都在别的文件里。
|
|
90
|
+
|
|
91
|
+
## 磁盘
|
|
92
|
+
|
|
93
|
+
`~/.dy` 会持续增长,但增长的几乎都不是 dy 自己的数据。实测一台用了几天的是 1.5G,其中 1.2G 是 Chrome 的 HTTP 缓存、104M 是截图,dy 的事件、记忆和人格一共 2.5M。
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
dy browser clean # 看能回收多少
|
|
97
|
+
dy browser clean --apply # 真的删
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
缓存和截图超过 512MB 时,Chrome 启动前会自动清一次。Cookie、登录数据、事件日志、收据、记忆、人格、快照永远不动。
|