Files
mcn-short-video/.workbuddy/memory/2026-09-03.md
T

525 lines
87 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-09-03 工作日志
## 后台自动化任务全量清空(~/.workbuddy/workbuddy.db automations 表)
- **背景**:用户询问「后台在执行什么任务,没用的任务是否可以清空」
- **盘点结论**(只读查询 workbuddy.db):
- 运行状态表 automation_runtime_state 58 条全部 `running=0`——**当前无任何任务在执行/排队**
- automations 表 66 条全部为 once 一次性历史任务(65 ACTIVE + 1 PAUSED),created 08-27~09-02,无 recurring
- 57 条已跑完(ACCEPTED/成功),1 条被 user_cancel 中断(导入指令·周小闹 PENDING_REVIEW),8 条从未运行(08-31 旧重复任务,已被 09-01 uuid 新版取代)
- **执行**:经用户确认「全部清空 66 条」,逐条 automation_update mode=delete(软删机制,置 deleted_at)
- **验证**:非软删有效任务 0 / 软删 66 / running=0;automation_runs 58 条运行历史保留(产物与会话回溯不受影响)
- **要点**:删除任务定义不影响 automation_runs 历史与已生成产物;工具删除为软删(deleted_at),表行物理保留
## 清理规则固化进技能(09-03,用户定红线:只清过期/错误失败任务)
- **背景**:用户问「WorkBuddy 不会自动清除过期任务吗」→ 答不会(实测:66 条积压 08-27~09-02 全保留,跑完仍 ACTIVE,调度器只扫未来时间不再触发但也不自动删)→ 用户要求「加入 skill,部署到用户环境也能执行,只能清理过期或者错误失败任务」
- **新增**:`references/接口调用/自动化任务清理规范.md`(源 V1.0)——触发场景(🧹后台任务清理,不创作)、判定标准(🟢过期已完成 once/🔴错误失败/PENDING_REVIEW/last_error/⚪从未运行死任务;**禁清** recurring/未来时间/running=1/QUEUED/IN_PROGRESS/deleted_at 非空)、执行步骤(只读 SQL 盘点→归档→列清单确认→**走宿主 automation_update 删除禁直改库**→复核)、实测事实(宿主不自动清理/删除不影响产物/工具删除幂等软删)
- **SKILL.md 挂载**:触发条件区新增 🧹后台任务清理 场景 + frontmatter updated_at→2026-09-03、last_change 追加
- **同步三处**:源 `D:\AgentSkill\mcn-video-script\project\短视频脚本创作\V1.0\`(=WorkBuddy 用户技能目录软链 `C:\Users\maidou\.workbuddy\skills\短视频脚本创作`→V1.0,md5 一致同一文件)+ dsh 副本 `C:\Users\maidou\.dsh\skills\short-video-script\`(独立副本,需手动同步,updated_at/deployed_at→09-03);Lite1.0 默认不动(08-26 同步策略)
- **重要事实(09-03 实测)**:`C:\Users\maidou\.workbuddy\skills\短视频脚本创作` 是 → `/d/AgentSkill/mcn-video-script/project/短视频脚本创作/V1.0` 的符号链接——改源技能即改 WorkBuddy 用户技能,dsh 副本才是唯一需手动同步的独立副本
## mcn-data-insight 复制进短视频创作技能 subskills(09-03)
- 用户指令:把 `D:\AgentSkill\mcn-data-insight` 复制到 `project/短视频脚本创作/V1.0/subskills/mcn-data-insight`,**去掉 git**
- 源结构:SKILL.md(实为 third-party-skills-index 索引,19K)+ references/规则/ + `.workbuddy/`(内含 memory 工作日志 / scripts 3个 py / **skills 13 个第三方子技能 4.2M**:douyin-account-diagnosis、douyin-ai-feed、douyin-content-surge、douyin-daily-hot、douyin-hot-trend、douyin-prohibited-word、douyin-search、douyin-top-account、douyin-weekly-surge、douyin-works-crawler、multi-copywrite-alchemy、nuwa-skill、playlet-douyin-feed)
- 执行:整目录 cp -r → 删副本 .git → 37M→4.3M;无嵌套 .git;`ls .workbuddy/skills/` 13 子技能齐全
- 注意点(未处理,待用户定夺):该 SKILL.md 目录树描述为平铺(douyin-*/ 在根),实际子技能全在 `.workbuddy/skills/` 下——复制保持原样,未改引用;是否要在父 SKILL.md 注册该 subskill 未做
## mcn-data-insight .workbuddy 重组(09-03 续,R6)
- 用户指令:`.workbuddy` 中的 scripts 放上级、skills 迁上级并改名 **subskills**
- 执行:`mv .workbuddy/scripts scripts` + `mv .workbuddy/skills subskills`;`.workbuddy/` 仅剩 memory(原项目历史日志,用户约定「历史日志保留原路径不变」→ 未改其内部路径)
- 引用同步:Python 批量替换 21 个文件(负向后顾保护 `~/.workbuddy/` 用户级路径):
- `.workbuddy/scripts/`→`scripts/`(root SKILL.md setup 命令、抖音数据规则.md、13 子技能 py 报错提示/SKILL.md/README)
- `.workbuddy/skills/`→`subskills/`(douyin-search SKILL.md 命令示例、抖音数据规则.md 存放路径节)
- douyin-account-diagnosis 两个 README「放入 .workbuddy/skills/」语义为用户级安装 → 改 `~/.workbuddy/skills/`
- root SKILL.md:技能清单 目录列加 `subskills/` 前缀 ×10、结构树按新布局重写(新增 scripts/ + subskills/13 子技能清单)、更新记录追加 2026-09-03 行
- 保留未动:SKILL.md 安全审计状态表 + L77「存档于 .workbuddy/security-audit-*.md」+ 更新记录历史行(报告文件本就不随包分发,属原项目历史存档,待用户定夺是否清理)
- 验证:非 memory 范围 0 残留裸 `.workbuddy/scripts|skills`;修改过的 py py_compile 全过
- 结构定稿:`mcn-data-insight/{SKILL.md, references/规则/, scripts/(3py), subskills/(13子技能), .workbuddy/memory/}`
- 待用户决定:①.dsh 副本是否同步该新子技能(dsh short-video-script 结构待确认)②memory 是否移出 .workbuddy ③安全审计表/历史存档行是否清理 ④子技能 douyin-account-diagnosis 内同名嵌套目录是否平铺
## 全技能树相对路径审计与规则固化(R7/R8,09-03 上午)
- 范围:短视频脚本创作 V1.0 全树(主技能+references/references-add/scripts+全部 subskills 及嵌套)相对路径全面审计
- 扫描结论:Windows/Unix 绝对路径命中几乎全为「环境判别锚点(D:/AgentSkill 是否存在/.dsh)/路径配置表/示例路径」按设计保留;browser-harness/envs/(conda venv)有 .gitignore `**/browser-harness/envs/` 兜底不随分发,豁免
- 真实修复:①V1.0/SKILL.md 七节「失误与规避记录.md」越级引用 `../../../` 改语义说明(技能包外文件、仅开发机;源+dsh short-video-script 两处)②mcn-dou-analysis/subskills/nuwa-skill-main 断链(README 多语言/COMMUNITY/CONTRIBUTING + fidelity-scorecard + sun-yuchen LICENSE)→ 官方 GitHub URL,源+dsh 副本同步(同 mcn-data-insight/nuwa-skill 上轮修法)
- 自有内容 md 断链复验 = 0(剩余仅第三方参考包 seedance 黑神话项目/openstreetmap 内部示例,豁免)
- **Task #78 规则固化**:新建 `references/规则/路径引用规范.md`(P0:相对路径铁律+允许项~占位/__file__/URL+禁令盘符/Unix/越级+豁免仅开发机工具·路径配置·示例·历史日志+自检方法),模板同步 V1.0+4 自有 subskills(mcn-data-insight/dou-analysis/video-prompt/script-review 各 references/规则/)+dsh 4 副本(short-video-script/dou-analysis/storyboard-prompt/script-review);5 源 SKILL.md+dsh SKILL.md 各挂 🔴 引用行(dou-analysis 表格锚点插入须放标题后非表头间——dsh 初插错位已修)
- 规则文档示例链接用 code 包裹防断链校验误报(某文件.md 占位)
- 提交:V1.0 20 项(14M+6??:含之前遗留 frontmatter/后台清理触发条款+自动化任务清理规范.md)
## R9 mcn-data-insight 收尾(09-03 上午)
- 用户 4 点决定:①删 `.workbuddy/memory` ②清理 SKILL.md 历史存档行(安全审计表/存档说明/更新记录历史) ③去 douyin-account-diagnosis 同名嵌套 ④**dsh 部署**;追加决定:nuwa-skill **整体删除**、multi-copywrite-alchemy **移至桌面**(理由「这里应该都是数据获取技能」)
- **★git rm 沙箱坑(重要,2 次踩)**:`git rm -r` 删百级文件在本沙箱被 SIGTERM 反复中断 → 结果=只删磁盘不写索引(全变 ` D` 未暂存)+ 留 index.lock + 中断时范围失控半删除(曾把整个 subskills 树删掉)。修法:`rm -f .git/index.lock` 清锁 → `git checkout HEAD -- <路径>` 从 HEAD 恢复误删 → **纯 `rm -rf` 删磁盘 + `git add -A -- <精确路径>` 暂存**(不经 git rm)。规律:git rm 触大范围删除必被杀;rm+add 分离安全
- 删除构成(157 文件):`.workbuddy/memory` 9 + 内层嵌套 10 + nuwa-skill 133(git 跟踪数;186 含非跟踪)+ multi-copywrite-alchemy 5;nuwa/multi HEAD 零残留
- SKILL.md 大清理:frontmatter/简介改「**抖音数据获取技能集**(Third-party Skills 百宝箱)」,技能清单**补全 11 行**(douyin-search/top-account/playlet 原缺列表,文件数=git ls-files 实测),删 multi(#5)/nuwa(#8) 两详情节+15 分身表,目录树 11 子技能,安全审计表整表删,更新记录精简为一行 09-03,详情节编号 1-8 连续重排(内容含两处双 `---` 修复);抖音数据规则.md 同步 13→11
- **技能定位定稿:mcn-data-insight = 纯数据获取技能集(11 个红狐系子技能)**;nuwa-skill 已删——注意 mcn-dou-analysis/subskills/nuwa-skill-main 是**另一份**(账号分析方法论组件,保留勿混)
- 提交 `eaecdd4`(159 files, -41007 行)已 push origin(f4f6938..eaecdd4)
- dsh 部署完成:`C:\Users\maidou\.dsh\skills\mcn-data-insight\` 新建(与源 diff=0、79 文件,无 .workbuddy)→ commit `2c3cf98`;**pycache 误入库**(scripts/__pycache__ 2 pyc)→ 清理 commit `9cee86a` + `.dsh/.gitignore` 追加 `__pycache__/`、`*.pyc`(V1.0 源仓库本就忽略,磁盘 pycache 已删)。dsh 2 commit 本地未 push(2h 节奏)
- 桌面迁移:`C:\Users\maidou\Desktop\multi-copywrite-alchemy\`(5 文件:SKILL.md + references×4)
## git 收尾(09-03 上午补录)
- dsh 仓库:未提交变更 = R1-R8 期间同步的规则(short-video-script 09-03 后台清理触发/frontmatter、script-review v1.3、4 处路径引用规范.md、自动化任务清理规范.md、nuwa-skill-main 3 处 URL 修复)→ commit `9a90e19`(12 files +367/-14)已 push origin(bc810f1..9a90e19,含 2c3cf98/9cee86a 共 3 commit)
- 源仓库 2 commit(本地未 push,2h 节奏):
- `116b7a2` 记忆维护(2026-09-03.md 追加 + MEMORY.md 压缩 22746→10416 字节)
- `d57b830` 历史遗留落地:**发现根 `dist/` 5 文件 = 用户早前移到 `project/短视频对话题分析/dist/` 的参考产物**(100% rename 识别,screenshot 存档不可再生)→ 纳入跟踪而非删除;case_1 案例目录 28 文件确认删除(磁盘早已删)
- 坑:`git add -A -- <中文路径>` pathspec 不匹配(bash 传参编码)→ 改全量 `git add -A`(先确认工作树只剩目标变更);rename detection 会把「删根 dist + 新位置 untracked」自动配对成 rename,commit message 需按 rename 语义写
## 达人账号表移出 mcn-dou-analysis 技能包(09-03 上午)
- 用户问「技能包内为何有达人账号表,不需要就删除」→ 查明:表是技能工作流登记台账(SKILL.md 红线 L42 15 列 + 功能一/二/六 7 处引用),但**内置副本=08-26 过期数据**(仅小咪橘座/旧梦留声机 2 账号),权威台账在**桌面 MCNSkill项目/达人账号表.xlsx**(含俊希 JJX0827/281.9万粉 08-31 更新、3 账号、数据更新)——技能包副本从未再更新
- 处理(用户指示本地文件放桌面 MCNSkill项目):删除技能包内置 xlsx(零数据损失,桌面份更全)+ SKILL.md 红线行/Step 1.0 + feature/01 两处改为「达人账号表=**外部数据文件不入技能包**(存放于产出根目录同层,表缺失按 15 列现场新建)」;feature/02/06 逻辑引用保留原文
- 提交 `5ccaaef`(源仓库,本地未 push)
- 待办:dsh 副本 skills/mcn-dou-analysis SKILL.md 同 7 处引用且无表文件——同步说明段需用户授权
- **dsh 侧澄清(用户确认)**:`D:/dshworkspace/达人账号表.xlsx`(08-26 17:28)= dsh 环境遗留死数据,**内容重复 2 遍(损坏导出)+ 停更 + 无俊希**,用户确认「dsh 数据已经没更新了」→ 不作权威、不维护、不同步 dsh 副本 SKILL.md。红线说明修正为「权威台账=桌面 MCNSkill项目 份(①③环境)」→ 提交 `aaafeec`
## 目录改名 R13:mcn-video-script → mcn-short-video(移交用户手动,09-03 上午)
- 用户要求本地目录与远程 git 名统一(origin 早已是 `mcn-short-video`)
- 已完成前置:3 处硬编码路径引用更新并提交 `7d6048c`(build-create-prompts.cjs L75、submit-review-tasks.cjs L30 数据库路径;mcn-dou-analysis SKILL.md L82 源技能路径);软链 `短视频脚本创作` 已删待重建
- **改名被占用阻塞(Device or resource busy 反复)**:根因=多进程持句柄/cwd——pwd 实证 Bash 工具自身 cwd 曾停在目标目录内;Bash cwd 切出后仍 busy → node 4444 等工作台服务 + WorkBuddy.exe 多进程仍持句柄(netstat/wmic/PowerShell 通道均无法取进程命令行取证,wmic 已不可用、PS 通道空输出)
- **结论:用户手动执行改名**(需完全退出 WorkBuddy 释放句柄后资源管理器重命名)
- 改名后收尾待办:①重建软链 `ln -s "/d/AgentSkill/mcn-short-video/project/短视频脚本创作/V1.0" "/c/Users/maidou/.workbuddy/skills/短视频脚本创作"`;②push `7d6048c`(当时唯一未 push commit);③grep 残留 `mcn-video-script` 引用(memory 日志除外)
- **09-03 11:12 用户决定搁置改名** → 软链已重建(指向当前 mcn-video-script 路径,技能恢复可用);7d6048c 预改名引用已 `git revert` 回退(`09bc9be`,3 处路径恢复 mcn-video-script 全树零残留);日志补录 `3de1c0f`
## 工作台任务模型跟随用户 AUTO(09-03 11:17 实证定稿)
- **问题**:用户问工作台任务能否跟随 WorkBuddy 模型选择(如 AUTO)——R11 已知 /api/run model_id 钉死 deepseek-v4-flash
- **机制实证**:①调度器 `modelId: row.model_id ?? void 0` + `setSessionModel` —— **model_id 有值必强制指定会话模型**(这就是全跑 flash 根因);无值(NULL)不强制走宿主默认;②用户 UI 模型选择是**会话级**的(sessions.model 列),最近 6 条手动会话全 `'auto'`(AUTO=系统按复杂度自动路由,小写存储);③66 条历史任务 65 flash+1 pro 无 auto/null 案例;④models.json 空、settings 无 model 键(非全局设置)
- **方案 A 落地(用户选 A)**:server.js /api/run L569 model_id `'deepseek-v4-flash'`→`'auto'`(加 09-03 注释含回退说明:若调度不认 auto 改留 NULL)
- **端到端实证通过**:提交测试任务「模型跟随auto验证」→ automations.model_id='auto' → 调度拾取创建会话 `98f73483` **model='auto'**(对比旧任务会话 model=deepseek-v4-flash)→ run ACCEPTED result_success=1、session completed。**调度 API 接受 'auto' 字符串且等效 UI 选 AUTO**
- 提交 `cf359f4`(源仓库本地未 push)。测试任务/会话已留在左侧会话栏(可忽略)
- 遗留:若日后想任务级精细选模型(flash/pro/auto)→ 方案 C 前端弹窗下拉+后端透传,未做
- 服务启动坑(重踩):Bash 工具 `&` 后台进程随命令结束被回收(8900 连接被拒)→ 必须 Bash `run_in_background=true` 启动长驻服务;curl 需 `--noproxy "*"`(全局 socks 代理 127.0.0.1:10800 拦截 localhost 报 upstream connect failed)
## 升级:动态跟随用户模型选择(09-03 11:22 定稿,替代固定 auto)
- 用户追问「能否真正做到用户在 UI 选什么模型任务就用什么」→ **能**。修正认知:WorkBuddy 模型无全局设置(models.json 空/settings 无 model 键),是**会话级**(sessions.model);且此刻用户最新活跃手动会话 model='deepseek-v4-flash'+thought='high'(非 auto——auto 是 09-02 旧会话)
- **实现**:/api/run 提交任务前动态读 `最近活跃手动会话(is_background_automation=0 AND model非空)的 model` 写入 model_id;无手动会话兜底 'auto'。用户在 UI 切 auto/flash/pro → 任务随之
- **端到端实证通过**:测试任务「模型动态跟随验证2」→ model_id='deepseek-v4-flash'(=当时最新手动会话 model,读取匹配)→ 会话 model=flash → run ACCEPTED result_success=1、session completed
- 提交 `cea7d11`(源仓库本地未 push)。cf359f4(固定 auto)+ cea7d11(动态跟随)两次演进均留史
- 待 push 累计:7d6048c/09bc9be/3de1c0f/cf359f4/cea7d11(5 commit,2h 节奏);左侧会话栏留 2 个验证任务(auto验证/动态跟随验证2,可忽略或清理)
## 榜单落盘规范 + 三方数据分层(commit 4c18e7e)
- 目录结构实证落定:桌面 `MCNSkill项目\` 顶层分「业务账号/三方数据」——账号产出直挂账号文件夹,三方数据统一下 `三方数据\{数据源}\`(当前数据源=红狐数据 → `三方数据\红狐数据\抖音榜单\` 已建);文件名**不加数据源前缀**(保 `抖音周榜_` 开头兼容 dsh RANKING_DIR 正则 `^抖音周榜_`)
- 规范固化点(5 处文档已同步):①主 SKILL.md「榜单数据落盘规范」落盘目标表+数据源分层说明;②抖音数据规则.md §2.1(含②dsh 列 D:/dshworkspace/抖音榜单/)+§2.2 示例目录指代+§2.4 幂等铁律;③三子技能 SKILL.md(douyin-daily-hot/content-surge/weekly-surge 落盘路径)
- ai-feed 历史 output 缓存 6 文件(08-07~09 json+html)git rm --cached 解跟踪;.gitignore 现含 subskills/*/output/ + subskills/*/*.json + 抖音榜单/ + *.log
- 待 push 累计:7 个本地 commit(d34ea02..4c18e7e),2h 节奏
## 榜单数据迁移 + 工作台读取路径改造(commit 5bd9dc0)
- 数据迁移:D:/dshworkspace/抖音榜单 27 个周榜 json(9赛道×3期 08-10/17/24)→ 桌面 `MCNSkill项目\三方数据\红狐数据\抖音榜单\`(mv 完成,源目录已空)
- 工作台 dsh-data.js RANKING_DIR 改为运行时判定:MCN_RANKING_DIR env 优先 > `.dsh` 部署(__dirname 含 .dsh)回退 `D:/dshworkspace/抖音榜单` > ①③ 开发机/用户环境 = 桌面 `MCNSkill项目\三方数据\红狐数据\抖音榜单`(os.homedir 真实桌面解析,候选 Desktop/OneDrive Desktop/OneDrive 桌面,fs.existsSync 探测)
- 服务重启(旧 PID 39616 Stop-Process → run_in_background 新启 DIi3hG)→ ranking 接口实测 450 条(9×3×TOP50)读取正常;前端无硬编码路径(全走 /api/dsh/ranking 只改后端即可)
## 赛道规则五次调整:剔除颜值造型(commit cdbbe48)
- 周榜保留赛道 7→6:生活vlog/小剧场/亲子/美食/情感/旅行;颜值造型移入排除 21(09-03 用户指令)
- 同步三处权威白名单:fetch_filtered_data.py KEEP_CATEGORIES+docstring(6/21)、抖音数据规则 §1 表+JSON+演进记录(五次调整)、douyin-top-account SKILL.md 周榜循环注释
- 缓存目录仍含颜值造型历史文件(3期)未删——按新规则后续不再获取,旧文件是否清理待用户确认
## 赛道规则六次调整:剔除情感 + 缓存数据清理(R20)
- 周榜保留赛道 6→5:生活vlog/小剧场/亲子/美食/旅行;情感移入排除 22(09-03 用户连续指令「颜值造型 去掉」「情感 去掉」)
- 同步三处权威白名单(同五次调整三处):fetch_filtered_data.py KEEP_CATEGORIES+docstring(5/22+六次调整注释)、抖音数据规则 §1 表/JSON/演进记录、douyin-top-account SKILL.md 周榜循环(5 赛道)
- **缓存目录数据清理(用户指令「去掉的赛道 现有数据也要删除」)**:删除全部已剔除赛道历史文件 12 个(颜值造型 3 + 情感 3 + 二次元 3 + 化妆美容 3),目录现仅保留 5 赛道×3 期 = 15 文件
- 验证:py_compile OK + 断言(保留=5 赛道,颜值造型/情感不在)+ ranking 接口实测 categories=5(美食/生活vlog/旅行/小剧场/亲子)dates=3 total=250 读取正常
- 教训:用户「情感 去掉」紧接「颜值造型 去掉」=连续精简指令,需完整执行不可只当上一条确认
## 工作台「账号周榜」入口 →「热点数据」多榜 tab 页
- 用户指令:「账号周榜入口改为热点数据,里面用 tab 区分数据列表,和首页一样」
- 改动:app.js 首页入口卡片 title 账号周榜→热点数据(desc 多榜切换)、CRUMB_TITLES.ranking + router titles.ranking→热点数据;data-pages.js renderRanking 重构为多 tab 页——RANK_TABS 四 tab(week 账号周榜/hot 视频热榜/likes 点赞榜/fans 涨粉榜,与首页 rank-preview 一致),week 显示完整周榜列表(筛选/排序/分页/关注,原逻辑保留),其余 tab 显示「建设中」占位(与首页行为一致,后端 RANKING_DIR 目前仅周榜 json,后续数据落盘即可接入)
- 验证:node --check 两文件通过;服务 8900 存活、新 js 已生效(grep 热点数据=3/1);带 ?v= 打开 #/ranking 页面
- 纯前端静态改动,server.js 未变无需重启服务
## git push 收尾 + docs 热点数据命名同步
- 两仓库 fetch 无分叉后 push:源 mcn-short-video d34ea02..a122760(13 commits,含榜单迁移/模型跟随/五调六调/热点数据页);dsh dsh_MCNProject 9a90e19..8fb747e(赛道五/六次调整)
- docs 遗留项:`mcn-work-shop/docs/AI会话任务输入输出对照.md` L21 入口 7 由「周榜(#/ranking / 首页)」改「热点数据(#/ranking 账号周榜 tab / 首页 rank-preview)」(commit e25168d,待下轮 push)
- 全工作台 md 复查「周榜|热点数据」仅此 1 处入口名引用,tab 内「账号周榜」名保留合理
## 补齐 douyin-rise-ranking(抖音涨粉榜)第 12 子技能(09-03 午后)
- **背景**:三榜 tab 对应技能确认(红狐官方链接 skillCode 映射:视频热榜 WqCrqrqr=douyin-daily-hot、点赞榜 M4zkHt29=douyin-content-surge、涨粉榜 EZTwMSse=**douyin-rise-ranking 本地缺失**)→ 官方仓库全套下载 `.workbuddy/tmp-rise/`(SKILL.md 304 行/README×2/core_workflow 284 行/dy-rank-api 98 行/gzh_growth_fetcher.py 841 行)
- **审计结论(安全 ✅)**:API Key 仅 env REDFOX_API_KEY 读取(env>shell 配置>提示,无硬编码);唯一写文件=自动写 `~/.workbuddy/cache/dy_rise_ranking_data.json`(单 key 覆盖多赛道=设计缺陷);无 subprocess/eval;命名 `gzh_growth_fetcher.py`+注释「供gen_gzh_html.py直接读取」=公众号技能复制改名残留
- **本地化 4 要点(落位 `subskills/douyin-rise-ranking/`,6 文件)**:①脚本改名 `douyin_rise_fans.py`(docstring/argparse 同步)②**去官方自动写盘缓存**:删 DATA_CACHE_FILE 常量/--from_cache 参数与分支/写盘块 → 纯 stdout(对齐本地「脚本零写文件,落盘归执行层」模式)③core_workflow.md:缓存描述→主 SKILL.md 落盘规范引用、查看更多改「读本地已落盘 JSON 的 account_list 21-50」、删「禁止子任务执行」声明(与 subskills 子技能定位冲突)、参数表去 --from_cache ④SKILL.md 重写为 daily-hot 精简式(触发词/安全约束含 `抖音涨粉榜_{赛道}_{日期}.json` 落盘/日周月时间判断/27 赛道/表格模板+涨粉分析三段式+订阅提示),README.md 重写(旧版残留 COZE_REDF0X 错键+CONFIG.json 已清),README.en.md/dy-rank-api.md 原样保留
- **真实冒烟通过**:`--rank_type week --category 美食 --raw --top_n 3` → status success、rank_date 2026-08-24(时间范围 24-30)、🥇书亦烧仙草 874.1万 7.2% +59.0万、三段式分析完整、account_list 50 条全字段、纯 stdout 未落盘
- **主 SKILL.md 4 处同步**:技能清单加第 12 行(文件数 6)、落盘规范表「4 涨粉榜」状态 ❌预留→✅已实现、目录树 11→12 + douyin-rise-ranking 行、更新记录追加一行
- **dsh 同步**:`C:\Users\maidou\.dsh\skills\mcn-data-insight\` cp 主 SKILL.md + douyin-rise-ranking 目录,diff=0,subskills 11→12
- **Edit 工具坑(重踩)**:同文件并行 Edit 有竞争(目录树改动未落盘,返回 success 却丢失)→ 同文件编辑必须串行/完成后 grep 复核;CRLF 文件多行 Edit 的 old_string 不匹配 → 行级 Python 替换脚本处理(归一化行尾);v1 脚本 R1 pattern 想当然漏中间三行 → 教训:pattern 逐字符抄 Read 输出,复杂删除改行级状态机
## 工作台删除「涨粉榜」tab(09-03 13:15,用户选「只删工作台 tab」)
- 用户指令「删除涨粉榜功能」→ 范围确认:**技能 douyin-rise-ranking 保留**,仅删工作台热点数据页/首页的涨粉榜 tab(三榜变两榜)
- 改动 2 文件(纯静态,无需重启服务):`mcn-work-shop/public/app.js` 首页 rank-tabs 删 fans 按钮行(L329)+ 注释「3 个新榜」→「2 个」;`data-pages.js` RANK_TABS 删 `['fans','涨粉榜'],` + L507 注释去涨粉榜
- 首页 tab 点击 handler 为通用逻辑(week=列表/其余占位)无 fans 特判,删按钮即自动收敛;cdp-verify-*.mjs 里的 `fans` 是**周榜表格粉丝列**(rk-num nth-child(5))非涨粉榜 tab,保留未动;docs/AI会话任务输入输出对照.md 仅提入口未列 tab 无需改
- 验证:node --check 两文件通过 + 服务 8900 伺服 js `grep -c 涨粉榜`=0;CDP 9224/9223 无调试浏览器未做视觉验证
- 已 push 源仓库 0cd2c45..09dc431(fetch 无分叉,跟踪引用正常未丢失);dsh 仓库无工作台副本无需提交
## 热点数据三榜接入:视频热榜/点赞榜 周粒度真实数据(09-03 傍晚)
- **任务链**:①写周粒度抓取器 `mcn-data-insight/scripts/fetch_week_ranks.py`(fetch_week_ranks.py,--board hot|likes|both + --date 周标号 + --force;服务端周窗口一次调用=likesRank 传周一~周日 / hotContentRank 传周日单参官方七日口径,**禁止逐日累加**)②落盘 2026-08-24 完整周:hot 28 赛道 1396 条 + likes 28 赛道 1400 条 → 桌面 `三方数据\红狐数据\抖音榜单\抖音周榜_{视频热榜|点赞榜}_{赛道}_{周一}.json` ③后端 board-aware:dsh-data.js parseRankFile/listRankFiles/rankingMeta(board)/getRanking(board)(DEF_KEY 随榜 week=comprehensiveScore/hot=likeCount/likes=add_digg_count;作品榜条目不查账号表 inDb 恒 false)+ server.js `/api/dsh/ranking` 透传 board(默认 week 兼容)
- **前端改造(本段)**:`data-pages.js renderRanking` 重写为 board 驱动三榜渲染——每榜独立 state(日期/赛道/排序/翻页切 tab 保留)、COLS 列模板(week=账号表 10 列含关注功能列;hot=排名/作品标题(链 workUrl)/作者/赛道/点赞/评论/分享/收藏/发布时间;likes=同构但 add_digg/add_collect/add_comment/add_share + create_time_str)、SORT_NUM 排序字段集合、defKey 回显默认降序箭头、meta 每榜独立缓存;`app.js` 首页 rank-preview 同步三榜——_PREVIEW_COLS 三模板 + setRankBoard 切榜重拉 meta、rk-video grid(8 列)CSS;style.css 加 .rk-tl 标题截断 + .table.table-rank.rank-video 列宽规则
- **验证**:node --check 三文件通过;node 直调 getRanking 三榜真实数据(hot 1396/likes 1400/week 250、美食筛选=50 条单赛道);重启 8900 服务(旧 36532 → 新 29172,cdp 冒烟 9224 无调试浏览器);curl 静态资源 200;内联渲染模板喂真实条目无异常
- **文档同步**:mcn-data-insight 主 SKILL.md 落盘规范表「2 视频热榜/3 点赞榜」❌预留→✅已实现 + 补 fetch_week_ranks.py 说明段;douyin-daily-hot/douyin-content-surge SKILL.md 补「日粒度归档走自身命名,周粒度由 fetch_week_ranks.py 落盘」边界;dsh 副本 mcn-data-insight cp 同步 4 文件(主 SKILL.md + fetch_week_ranks.py + 2 子技能 SKILL.md)
## ★热点数据三榜修正:全品类单文件+三子目录(09-03 晚间,用户纠正全赛道误读)
- **用户纠正(重要)**:「全赛道获取所有数据」= **不传 type 一次调用拿全品类**,非按 28 赛道循环;批评「整这种浪费钱的操作前先问问」。教训三层固化:①抓取器 docstring + SKILL.md 成本铁律「多赛道/多日/多窗口付费调用前必须先向用户确认次数与范围」②本日志 ③失误复盘见上
- **API 实测结论(固化防再探测)**:likesRank 无 type=50 条全品类周榜(source 抖音每日热门作品榜-GitHub,周一~周日);hotContentRank **source 必须「抖音每日点赞飙升榜」生产名**(写「抖音七日点赞飙升榜-GitHub」返回空),无 type=50 条(startTime=周日七日口径);**单次上限 TOP50**(limit=100/page=2/offset=50 全被忽略)
- **新落盘契约**:`抖音榜单/` 三子目录 `账号周榜/`(抖音周榜_{赛道}_{周一}×多期,douyin-top-account 落盘)、`视频热榜/`(抖音周榜_视频热榜_{周一}.json 全品类单文件/期)、`点赞榜/`(抖音周榜_点赞榜_{周一}.json);旧 28 赛道 56 文件归档 `_archive_旧28赛道结构_20260903/`;顶层 category="全部",赛道在 list[].category
- **后端改造**:dsh-data.js RANK_SUB 子目录映射 + rankFilePath(dir,name) + parseRankFileIn/listRankFiles(子目录优先+根目录旧平铺回退)/collectCategories(week=文件名赛道;hot/likes=条目 category 并集)/getRanking 赛道过滤(week 文件名级、hot/likes 条目级);工作台实际读取桌面目录(源技能 __dirname 无 .dsh → 桌面 71→15+2 文件;D:/dshworkspace/抖音榜单 为空是 dsh 部署形态)
- **验证**:node --check ✓;node 直调 week 250/3期/5赛道 + hot 50/12赛道 + likes 50/14赛道;筛亲子 hot=2/likes=3;服务重启(29172→3912)curl 三榜 API 全通;前端赛道下拉动态(meta.categories)无需改动
## 工作台赛道白名单过滤(09-03 15:05,用户要求「只留所需赛道」)
- **需求**:热点数据页赛道筛选下拉与列表(含「全部」)只保留所需赛道数据
- **口径**:与账号周榜 douyin-top-account 保留 5 赛道一致;**账号榜 type=生活vlog / 作品榜条目 category=生活记录**(两套枚举),白名单取并集 RANK_KEEP=['生活记录','生活vlog','小剧场','亲子','美食','旅行'](dsh-data.js)
- **实现**:collectCategories 白名单∩实际出现(按 RANK_KEEP 顺序);getRanking hot/likes 条目无条件白名单过滤(「全部」也只留白名单)+ 请求赛道过滤;week 不受影响
- **验证**(服务 5500):week 下拉 5 赛道/250 条不变;hot 下拉[生活记录,小剧场,亲子,美食]全部 29 条;likes 下拉[生活记录,小剧场,亲子,旅行]全部 28 条;当期 0 条赛道(hot 旅行/likes 美食)不进下拉
## 热点数据 UI:入口改名 + tab/筛选同行(09-03 15:10)
- 入口卡(首页 data-card)title「账号周榜」→「热点数据」,desc→「账号周榜 · 视频热榜 · 点赞榜」;CRUMB_TITLES ranking 同步改「热点数据」(原与 page-title 不一致)
- data-pages.js renderRanking:tabs 并入 toolbar 一行(返回|标题|三榜tab|右侧赛道下拉+◀日期▶),删独立 tabs() 输出 3 处;错误/空态也带 tab 可切换
- CSS:.page-toolbar .rank-tabs 行内化(border-bottom none、margin 0、center)
- index.html 静态引用加 ?v=20260903 版本参数(防缓存旧 js/css;今后改动记得 bump)
- 服务无需重启(静态),curl 资源全 200
## R24 三榜 tab 悬停气泡「近7日数据」(09-03 追加)
- 用户要求:视频热榜/点赞榜 tab「后面加个信息图标 hover 提示近7日数据」→ 澄清后改为**不加图标,纯悬停提示**
- **最终方案(用户定)**:tab 上直接 hover 停留约 2 秒浮现「近7日数据」气泡。实现=纯 CSS:button 加 `data-tip="近7日数据"`,`:hover::after { content: attr(data-tip); opacity:1; transition-delay:2s; }`,基础态 transition 无 delay → **进入延迟 2s、移开立即淡出**(关键:delay 只写在 hover 规则里)
- 覆盖两处同构 tabs:data-pages.js renderRanking RANK_TABS(第三字段 tip,动态拼 data-tip)+ app.js 首页 rank-preview(静态 button 直写)
- 回滚了先做的 info 图标版(ICON_PATHS 'info'、.rank-tab-info span)——用户不要图标,避免死代码已删净
- index.html 版本参数 bump 至 ?v=20260903c;git 75e1846(连同 acb4c3e 一起 push,052550e..75e1846)
## R24 更正:tab 信息图标版定稿 + 首页统计条/入口改名(09-03 续)
- **R24 更正**:上文「悬停气泡」为方向误解,用户原意=**tab 文字后加 ⓘ 信息图标,鼠标指上去(title)显示「近7日数据」**。定稿=span.rank-tab-info{svgIcon('info',13) title=近7日数据}(RANK_TABS 第三字段 tip,hot/likes 有、week 无);CSS .rank-tab-info opacity .5/hover .9,跟随文字色无底色。commit 8719ae5(含首页统计条「热门账号」→「关注账号」,前端 app.js L311 静态占位+L357 动态 items 两处,L111 移植来源注释不改)
- **脚本诊断入口改名**(用户:「AI脚本诊断功能入口改为脚本诊断」)commit 56a3ea5:首页功能卡 title/CRUMB_TITLES reviews/路由 titles reviews/reviews 页 page-title 四处 AI脚本诊断→脚本诊断;**首页统计条保留 AI脚本诊断**(与「AI脚本评分」并列保 AI 前缀齐整,如需同改一句话跟进)
- **教训(同文件多 Edit 并行互相覆盖)**:同文件不同位置多个 Edit 并行提交只部分生效(L306/L706 落空一次、早前 L357 同坑)→ **同文件修改必须一次一个 Edit 串行,改完 grep 逐处核对**;git add/commit 链命令在 escalated 重跑时首跑常显示 nothing to commit 属假象(实际已提交),以 git log 为准
- index.html 版本参数已至 ?v=20260903e
## R24 终稿:tab 去图标改原生 title 悬停提示(09-03 再次确认)
- 用户最终拍板:**不要 ⓘ 图标**,鼠标悬停到「视频热榜/点赞榜」tab 上自动显示「近7日数据」即可 → 定稿=原生 `title="近7日数据"` 属性(与全站按钮 hover 提示惯例一致,浏览器默认延迟约 1s,无自定义样式)
- data-pages.js RANK_TABS 第三字段 tip 动态拼 title;app.js 首页 preview 两 tab 静态 title;ICON_PATHS 'info'、.rank-tab-info CSS 全部删净(0 残留)
- 教训沉淀:图标方案两度反复(图标→气泡→图标→title),根因=未在动工前确认交互形态;今后 UI 交互类需求先 1 问确认(图标+tooltip / 纯悬停)再改
- git 2909220(56a3ea5..2909220,含 97dae59 日志提交);index.html 版本 ?v=20260903f
## R25 首页 AI脚本卡片右下角显示脚本评分(09-03)
- 需求:AI 脚本若有对应评分 → 显示在卡片右下角;无评分不显示
- 后端 dsh-data.js listRecentScripts 增加标量子查询:取该 rewrite 最新一条已完成的 AI 复盘总分(script_review type='ai' AND rewrite_id=r.id AND status='done' AND total 非空 ORDER BY id DESC LIMIT 1)AS score,无复盘=null
- 前端 app.js loadRecentScripts:卡片底部改 .recent-card-foot 双栏(meta 左 flex:1 / 徽章右),有分渲染 .recent-card-score 圆角徽章「评分 X」,配色同诊断页 scoreColor(≥75 绿 #3a9e6d / ≥60 橙 #d99a2b / <60 红 #d9534f,hex+1a 透明底);无分(null/''/undefined)不输出
- CSS:meta 的 width:100%/margin-top:auto 迁到 .recent-card-foot(底部行整行推底)
- 验证:工作台库 mcn-plugin.db(**非 ~/.dsh/mcn-plugin.db**,两库隔离)26 done 脚本 16 无评分;API limit=20 → 有分10/无分10,null 双路径确认
- **重启服务才生效**(dsh-data.js 后端模块,旧 PID 5500→新 23268,taskkill 单斜杠);git 436cfb3;版本 ?v=20260903g
## R26 AI写脚本页 tab 与搜索筛选同行(09-03)
- 需求:AI写脚本(#/rewrites renderRewrites)页 tab 组件与搜索/筛选组件放一行
- data-pages.js:.rw-tabs div 从 toolbar 下独立行移入 .page-toolbar(返回|标题|tabs|toolbar-right 筛选右),加 rw-toolbar-tabs 类;rw-note 留在 tab 行下方表上方
- style.css:.page-toolbar .rw-tabs 行内化(border-bottom none/margin 0/padding 0/center),tab 压缩 13px;tab-active 保留下划线条
- 纯静态改动无需重启;git 待查;版本 ?v=20260903h
## R26 AI写脚本页 tab 与搜索筛选同行(09-03)
- 需求:AI写脚本(#/rewrites renderRewrites)页 tab 组件与搜索/筛选组件放一行
- data-pages.js:.rw-tabs div 从 toolbar 下独立行移入 .page-toolbar(返回|标题|tabs|toolbar-right 筛选右),加 rw-toolbar-tabs 类;rw-note 留在 tab 行下方表上方
- style.css:.page-toolbar .rw-tabs 行内化(border-bottom none/margin 0/padding 0/center),tab 压缩 13px;tab-active 保留下划线条
- 纯静态改动无需重启;git 待查;版本 ?v=20260903h
## R27a AI写脚本页布局修正(09-03,R26 返工)
- 用户澄清:R26「tab 与筛选同行」≠ 并入标题行;且追加要求筛选搜索也移下标题行
- 终局结构:page-toolbar 只留 返回|标题「AI写脚本」;其下 .rw-tabs 单行 = 左三个 tab + 右 toolbar-right(搜索/时间/状态,margin-left:auto),rw-tabs 加 align-items:center
- 还原教训:R26 把 tabs 并入 toolbar 标题行属误读「放一行」,用户两次纠正(先 tab 放下、再筛选也放下)
- 状态列:ref tab「✅已解析」去图标改浅绿文字(.st-parsed #52b788,font-weight 500);「未解析」保持默认
## R27 账号列表 重置按钮 → 更新按钮(09-03,口径已确认)
- 口径(AskUserQuestion 确认):范围=⭐ 已关注(favorite=1 共 3 个:做夢/平凡的胡德禄/旧梦留声机);交互=确认弹窗后执行
- data-pages.js:L700 accReset(纯 refresh 图标)→ accUpdate「refresh 图标 + 更新」;L733 重置绑定 → updateFollowedAccounts(btn)
- 新函数 updateFollowedAccounts(renderAccounts 后,文件级):GET /api/dsh/accounts pageSize=100 → filter favorite → 自建 modal 确认(confirm-target 列名单)→ 逐账号串行 POST /api/run(prompt=SKILL_HINT_ACCOUNT +「更新已登记账号」语义:浏览器重抓账号信息+视频列表覆盖更新、身份标识禁库中旧值回填;name='更新账号·X';skills mcn-dou-analysis)→ 轮询 /api/run/status(每 5s,单任务 20min 上限;done/error/review/notfound/超时 五终态)→ 按钮「更新中 i/N…」→ 汇总 toast + refreshCurrentPage
- 串行理由:多会话并发会抢浏览器 9223 调试实例;executeTask 单按钮封装不适配 N 任务,自写轮询
- 未验证:首次实点后需核对任务侧能否覆盖更新 hot_accounts 主表(server.js importAccountIntoDb 不写 hot_accounts 粉丝/获赞/作品数——只 upsert 视频解析/人设/视频列表/拆解;技能侧登记链路待实测)
- 纯静态改动无需重启;版本 ?v=20260903j
## R28 视频详情页:去「视频分析」tab + 未解析「解析」/已解析「刷新」按钮(09-03)
- 需求:视频详情页(renderVideoDetail)视频脚本/视频拆解 未解析时空态加「解析」按钮;已解析内容右上角加「刷新」按钮;去掉「视频分析」tab(analysis 数据保留不入展示)
- data-pages.js:①顶部新增 SKILL_HINT_VIDEO_PARSE(mcn-dou-analysis 功能五 F5:upload_douyin_video→detailId→sleep→short_video_detail→json_tool.py 落盘 content.json/analysis.json→工作台 POST /api/import/account 入库);②tabBtns 删 analysis;③body 分支:scriptMd/deconstructMd 有→.vd-tools(右上刷新 data-parse=refresh)+md-body;无→.empty-state+解析按钮(data-parse=parse);④新增文件级 confirmVideoParse(btn,v,mode):confirmRun+executeTask 单任务,prompt=SKILL_HINT_VIDEO_PARSE+链接/标题/达人,label 解析指令 skills mcn-dou-analysis;tab 绑定后统一绑 [data-parse]
- style.css:.vd-tools(flex 右对齐,margin 2px 0 8px 20px 对齐 page-detail md-body 缩进)
- 冒烟 cdp-verify-r28.mjs(9225):未解析58=2 tabs(无分析 tab)+双 tab 空态解析按钮+解析弹窗;已解析117=vd-tools 刷新按钮(icon);deconstruct 无 analysis→空态解析(符合分支)全 PASS
- 版本 ?v=20260903k;待实测:解析完成后 account_video_source 更新链路(F5 产物在 视频对标/ 目录,import/account 只扫 视频分析/——需看技能侧 backfill 或 import 扩展)
## R29 账号详情视频列表加「标签」列(09-03 收尾)
- 需求:视频列表中「时长」前增加标签列,宽度固定 40px,鼠标停留显示完整标签
- data-pages.js renderAccountDetail(#/account/{id}/persona 视频列表 tab):①L869 数据行在 collect_count 后、duration 前插 `<td class="td-tag"${v.tags?title:''}>`(title=完整标签悬停);②L921 表头 收藏 后插 `<th class="th-tag">标签</th>`;③colspan 8→9/batch 9→10。数据源 account_videos.tags(listAccountVideos SELECT v.* 已带出;格式逗号分隔 # 话题)
- style.css:.table th.th-tag(40px/min-width 40/居中/收 padding)+ td.td-tag(max-width 40 + ellipsis 省略 + nowrap)
- 冒烟 cdp-verify-r29.mjs(9225 新 profile r29):表头 9 列序=…收藏|标签|时长…、th 实测宽 40px、首行 td-tag 视觉截断(scrollWidth>clientWidth)+title 完整含 #、无 num 类 全 PASS
- 版本 ?v=20260903k→l
- MEMORY.md 二次压缩 11148→7213 字节(注入截断修复)
## R30 列表页 toolbar 拆行(09-03 收尾)
- 需求:所有列表页标题行只放 返回+标题,tab/筛选/搜索/功能按钮一律放标题下一行;账号列表重点检查
- 审查 6 个列表页 render 函数 → 违规 2 个:
- renderAccounts(L689-705):原 page-toolbar 内 toolbar-right(类型/赛道下拉 + 搜索 + 添加 + 更新) → 拆出
- renderHot(L521-538):原 page-toolbar 内 rank-tabs(3 tab) + toolbar-right(赛道/日期) → 拆出
- 合规页(仅返回+标题):renderAccountDetail / VideoDetail / Rewrites(R27 已修) / Reviews(pager-info 是统计信息非功能)
- data-pages.js:①renderAccounts 拆为 `<div class="page-toolbar">返回|标题</div> <div class="acc-toolbar"><div class="toolbar-right">筛选+按钮</div></div>`;②renderHot 拆为 `<div class="page-toolbar">返回|标题</div> ${withFilters ? '<div class="rank-toolbar"><div class="rank-tabs">3 tab</div><div class="toolbar-right">赛道+日期</div></div>' : ''}`
- style.css:`.acc-toolbar { display:flex; gap:10px; flex-wrap:wrap; margin:-20px 0 16px; padding:0 4px; }` `.rank-toolbar { display:flex; gap:14px; margin:-8px 0 16px; padding:0 4px; }` `.rank-toolbar .rank-tabs { flex:1; }`
- **间距差异化**(09-03 用户反馈后拆开):账号列表 -20px→4px(工具栏紧贴标题,功能性组合) / 热点数据 -8px→16px(tab 区段独立感);初版 -12px 一致 12px 用户反馈账号列表太远+热点太近
- 冒烟 cdp-verify-r30.mjs(9225):账号列表+热点数据+AI写脚本回归 三页 toolbar 仅含返回+标题、功能组件均下移 PASS
- 版本 ?v=20260903m→n→o;commit e858929
## R29 列位移+列宽 60px(09-03 收尾)
- 用户**三遍**指示「放在点赞列左边」;我首次按字面「时长前面」实现(时长左一列=收藏与时长之间)→ 修正为 视频标题与点赞之间
- data-pages.js 表头/数据行同步移动 td-tag;版本 ?v=20260903o→p
- 后续:用户要求标签列宽 40→60px(容纳更多标签字符),style.css 同步调整,版本 ?v=p→q
- 冒烟 cdp-verify-r29.mjs 同步更新断言:thTagIdx 6→2, tagBeforeDur→tagBeforeLike, thTagW/tagTdW 40→60, navigate 加 ?v= 强制拉新 CSS
- commit f5b4103(列位移) / 列宽60单独 commit;失误记录 #014 沟通歧义沉淀
## R31 junction 失效修复:短视频解析「无法加载 skill」(09-03 收尾)
- **现象**:短视频解析任务会话显示「无法加载 skill」
- **排查**(node lstat 实测):`C:\Users\maidou\.workbuddy\skills\短视频脚本创作` 本应是指向 `D:\AgentSkill\mcn-video-script\project\短视频脚本创作\V1.0\` 的 junction,实测 isSymbolicLink:false、isDirectory:true、children=0(**空目录**,时间 09-03 11:11,与源技能同步同一分钟,疑似 WorkBuddy 宿主扫描/迁移逻辑把 junction 替换成空目录);源技能 V1.0 完好(SKILL.md+6 subskills 均在)
- **影响范围**:不止解析任务——所有 SKILL_HINT_*(主技能创作/复盘/分镜/解析)都从该路径加载,目录空=Skill 工具全部报无法加载
- **修复**:①bash `rmdir` 空目录(需目标为空才成功)→ ②`New-Item -ItemType Junction`(**目标路径必须已删除否则 exit 1**——上次修复失败根因)
- **验证**:node lstat isSymbolicLink:true / children:7 / SKILL.md md5 与源一致(9dad72ab...)→ 同一文件
- **工具坑(本会话)**:PowerShell 工具输出通道不可用(ConPTY off,stdout 被吞,exit code 仍有效)→ 诊断改 Bash、PowerShell 结果写文件再 cat 验证
- **复发防范**:征兆=任何技能加载失败先查该路径 children==0;修法已写入 MEMORY.md 核心技能节
- 待用户重试解析任务验证端到端加载(会真实调用 MCP)
## R32 技能更名:短视频脚本创作 → 短视频工作台(09-03)
- **需求**:技能对外名称统一为「短视频工作台」(用户给对象=`D:\...\project\短视频脚本创作\V1.0`);选 B 完整档(name+按名引用+注册目录/junction 全改);Lite 跟随改名
- **边界(关键决策)**:repo 目录 `project/短视频脚本创作/` **保留原名**(工程结构/版本家族语义),只改「注册/显示名」层;流程术语(创作师/协作流程/系统)与产品历史文档、失误记录 append-only 保留
- **P0 必改**:V1.0 SKILL.md frontmatter name→短视频工作台+标题+last_change 前缀;Lite1.0 name→短视频工作台 Lite;data-pages.js `skills:['短视频工作台']`×3(L497/992/1306)+SKILL_HINT_CREATE 加载名+5 个 HINT 常量内 `~/.workbuddy/skills/短视频脚本创作`→`短视频工作台`;app.js SKILL_HINT_ACCOUNT 同;server.js 注释
- **P1 文档**:dou-analysis SKILL.md L51/L60 主技能指称(repo 路径 L82/L108/L118 保留)、浏览器操作规范 2 处、script-review Scope、docs/AI会话任务输入输出对照.md 契约表 skills×3、自动化任务调度机制.md L81、帮助文档标题×2(V1.0/Lite)
- **全量替换安全判定**:先 grep 确认 3 个 JS 无 `project/短视频脚本创作` repo 路径字面量 → 才可 replace_all
- **junction 重建**:node `unlinkSync` 删旧链(rmdir 对 junction 报 Not a directory)→ PowerShell New-Item Junction `短视频工作台`→`D:\...\project\短视频脚本创作\V1.0\`;验证 isSymbolicLink:true/children:7/frontmatter name=短视频工作台/md5 一致
- **残留核查**:全仓剩 35 行全部可保留分类(产品叙事 13/流程术语 4/能力描述+变更记录 4/历史审计 4/repo 路径字面量 9/失误记录 1),技能名指称清零
- 版本 ?v=20260903r;commit 057522c
- **待办**:用户环境安装包技能名=短视频工作台(仅剩此项,dsh 已同步见下)
- **R32 补完:dsh 副本同步改名(09-03 16:5x,commit 5bc1f49)**:用户「按方案 B 完整档修改」授权 → 同步 `C:\Users\maidou\.dsh\skills\short-video-script\`:SKILL.md name→短视频工作台 + description 前缀「短视频工作台(短视频脚本创作全流程技能):」+ 标题 `# 短视频工作台 Skill` + last_change 前缀照源 V1.0 写法追加改名记录;帮助文档 L1→`# 短视频工作台 — 使用指南`(源格式无「技能」字样);deployment:"dsh"/deployed_at 保留;残留 5 处全保留(description 括号能力描述/last_change/L22 能力描述/references 创作师角色 2)与源处理一致;git add 精确两文件,不混入 .dsh 仓库其他未提交变更(mcn-data-insight 等仍在工作区)
## R33 工作台榜单页「更新」按钮(09-03 晚间)
- **需求**:热点数据三榜页加更新图标(用户中途改纯图标去文字),点击确认后后台任务重抓三榜最新一期并落盘;执行前检查上次更新防重复
- **后端 server.js 顶层新增**:`RANK_UPDATE_NAME='更新榜单数据'`(固定任务名=防重识别键)+ `RANK_UPDATE_COOLDOWN_MS=30min` + `wbDb()`(宿主库 `~/.workbuddy/workbuddy.db`)+ `createOnceAutomation(name,prompt,skillsArr)`(自 /api/run 抽公共一次性任务创建:once+next_run_at +5s/owner 取最近会话/model 动态跟随/skills 参数级挂载)+ `rankLastTaskState()`(按固定任务名查最近状态,running/queued/pending=进行中)
- **接口**:`GET /api/dsh/ranking-update` 返回新鲜度(exists/files/latestMtime→lastUpdateAgeMin/lastUpdateDate/cooldownMin/task);`POST {prompt,force}` 双层防重:①任务进行中直接拦截 ②距上次落盘 <30min 且未 force → `needForce:true`;通过则 createOnceAutomation(name, prompt, ['mcn-data-insight'])
- **数据层 dsh-data.js `rankingFreshness()`**:递归扫 RANKING_DIR(三榜子目录 账号周榜/视频热榜/点赞榜 + 根旧平铺回退)全部 .json → latestMtime/latestFile/latestDate/files(=最近成功落盘时刻)
- **前端 data-pages.js**:`SKILL_HINT_RANKING` 常量(mcn-data-insight 更新语义:fetch_week_ranks.py --board both 全品类单次 + douyin-top-account 5 赛道 + 幂等铁律 ls 跳过跳 API + 环境落盘目录)+ toolbar 标题行右 `.toolbar-right` 加 `#rankUpdate`(**纯图标**:`.btn-icon` + svgIcon('refresh',16) + title 悬停说明全链路)+ `updateRankingData()`:GET 状态→running 拦截 toast→确认 modal(上次更新时间/三榜范围;冷却窗口内黄字警示 `#b7791f` 按钮变「仍要更新」=force)→ POST→轮询 15min 上限→完成 `view._reload=null; router()` **整页重建**(meta 缓存闭包内,不重建拉不到新数据期);busy 态**不动 innerHTML**,改 title='榜单更新中…' + `.btn-busy` 类图标旋转
- **style.css**:`.btn-icon`(padding 5px 9px inline-flex center)+ `.btn-busy .ic`(animation: req-spin 1s linear infinite,复用弹窗 spinner)
- **成本铁律**:modal 明示约 7 次红狐 API(2 作品榜调用 + 5 赛道账号榜),用户确认即豁免;抓取器幂等 ls 命中跳 API 防重复花钱
- **版本**:index.html ?v=20260903r→s→t(style.css+data-pages.js 均到 t)
- **验证**:node --check 3 JS ✓;curl --noproxy GET 状态正常(files=73/lastUpdateAgeMin=124/task=null);POST 空 prompt 400;CDP 冒烟 `tmp/cdp-rank-update-smoke.mjs`(9225)纯图标版 9 项全 PASS(text='' + svg + title + modal 标题/三榜范围/上次更新/按钮文案/取消)
- **服务/工具坑(重踩)**:nohup+& 后台 node 随 bash 退出被回收 → 须 Bash run_in_background 直接托管前台;taskkill //PID Git Bash 语法错 → PowerShell Stop-Process -Force(返回 exit 1 但端口已释放);curl 全局 socks 代理 502 → 必须 --noproxy '*'
- **待实测**:首次真实点击任务链路(调度拾取→技能会话→抓取执行→落盘→页面重建出最新期)
## R34 工作台「脚本详情统一弹窗」三入口共用(09-03 晚间)
- **需求**:首页 AI脚本卡 / AI写脚本「N 查看」/ 脚本诊断页标题 三处点击后展示同一弹窗;右侧内容由「AI分镜提示词」改为可切换「脚本诊断 | 分镜提示词」两个 tab,默认显示「脚本诊断」(用户指定)
- **范围**:用户选「三处入口统一升级 (Recommended)」——合并两套重复弹窗代码(`openRewriteCompare` AI写脚本页 / `openScriptDetail` 诊断页)+ 首页 `openRecentScript` 接入
- **顶层组件** `openScriptModal({ rewriteId, videoId })`(data-pages.js 取代两旧闭包):
- 数据装配:`vid>0` ref 走 `Promise.all([/api/dsh/video-script?videoId, /api/dsh/video-detail?videoId])`;`vid===0` custom 走 `/api/dsh/custom-script?id`(拒绝时回退 `/api/dsh/rewrites` 全表定位,若挂 video 则递归转 ref 形态);全空 → toast「该脚本不存在或已删除」
- 状态:`stab='diag'`(默认诊断)、`showSrc`、`sbIdx`、`verIdx`;`visibleSbOf(curId)` 按 rewrite_id 归属过滤
- 诊断口径:`review-full` 的 ai 或 compare 取一(compare 取 AI 视角 dims/total 与源对比分);11 维 DIAG_DIMS;无诊断 → 「该版本 AI 脚本尚未诊断」+ 开始复盘按钮
- 分镜边界:仅 ref 有(storyboard_log 需 video_id);custom 无视频载体 → 空态「该脚本为自定义选题(无关联视频),暂不支持分镜提示词」+ 无生成按钮(禁止 confirmRun 空视频)
- 复盘触发:有源 → 三模式复盘(AI/源/对比);无源 → 独立分析仅评 AI 脚本(与诊断页行按钮同文案)
- 完整报告:`reportFullReview(reviewId)` 顶层函数副本(原 openReviewDetail 弹窗逻辑抽全局,跨页复用)
- 场次滚动联动:仅 `stab==='sb'` 且有分镜时(AI 列滚动 → 分镜列对齐场块,分镜列不反向联动),sideSec 用 `.rw-side-tabs` 存在判定、aiSec 用 head 文本 startsWith('AI脚本') 判定
- **删除旧闭包**:`openRewriteCompare`(含内嵌 renderSbBlocks)+ `openScriptDetail`(node -e 锚点切割,各 -7139/-6799 字符);衔接点 grep 验证零残留 renderSbBlocks/openRewriteCompare/openScriptDetail 引用
- **app.js 首页接入**:`openRecentScript(s)` 优先 `window.DataPages.openScriptModal({ rewriteId: s.id, videoId: s.video_id })`;原单列全文弹窗降级兜底(data-pages.js 未就绪时)
- **style.css 新增**:`.rw-side-head`/`.rw-side-tabs`/`.rw-side-tab`(pill tab 容器,默认透明)
- **版本**:index.html ?v=20260903u→v(CSS 有 tab 底色修复须强制刷)
- **CDP 冒烟** `tmp/cdp-r34-modal-smoke.mjs`(9225):reload ignoreCache→首页卡点击 → 弹窗三列 / 两 tab / 默认诊断 / AI列存在 / 源收起 / 诊断渲染 / 切分镜 / 分镜空态 / 关闭 / 诊断页入口同弹窗 / AI写脚本查看同弹窗;JS 版本=20260903v 时 **16 PASS 全绿**
- **CSS tab 底色修复(09-03 末)**:用户反馈「切换内容的按钮不要用深蓝色底色,文字变色就行」→ `.rw-side-tab.active` 去 `background: var(--primary); color: #fff;`,改 `color: var(--primary); font-weight: 600`;hover 同步去 rgba 浅蓝底;CDP 计算样式验证:active `bg=rgba(0,0,0,0) color=rgb(47,111,237) weight=600`,符合「文字变色就行」
- **冒烟断言修复(关键)**:初版 C2 断言 `!![data-vnext] || !!.rw-sec-count` 对 videoId=185(仅 1 个 rewrite id=20,单版本)误判 FAIL——组件按 `rewrites.length>1` 才渲染版本切换控件,单版本无控件是正确行为;改为二分合法态:AI列正文渲染 + (无版本区 = 单版本合法) / (有 count = 验证「版本 x/y」格式);重跑全绿
- **代码删除纪律再踩(教训固化)**:同文件多 Edit 并行执行会互相覆盖(本次 3 处 index.html 版本 bump 并行,只存活 app.js 一处)——**同文件 Edit 必须串行**,并行 Edit 仅适用于不同文件
## R34 样式打磨(09-03 末,w 版)
- **tab 底色修复**(用户反馈):切换内容的按钮不要用深蓝色的底色,文字变色就行 → `.rw-side-tab.active` 去 `background: var(--primary); color: #fff;`,改 `color: var(--primary); font-weight: 600`;hover 同步去 rgba 浅蓝底;CDP 计算样式验证:active `bg=rgba(0,0,0,0) color=rgb(47,111,237) weight=600`
- **空态主操作按钮统一**(用户反馈):开始复盘 + 生成分镜 两按钮「一个样式」 → 统一 `btn btn-sm btn-view`(白底蓝字蓝边,复用弹窗主操作家族「展开源脚本」「开始复盘」原有风格);CDP 实测两按钮计算样式完全一致
- **版本**:data-pages.js ?v=20260903v→w(CSS 没改保持 v,app.js 保持 v)
- **冒烟回归**:w 资源下 `tmp/cdp-r34-modal-smoke.mjs` 16/16 PASS 无回归
## R35 工作台「更新数据」按钮统一下载图标(09-03 17:30)
- **需求**:用户反馈「更新数据用 互联网下载那个图标,按钮宽度在宽5px」→ 后续补「包括账号列表的 更新按钮 统一样式」
- **改动**:
- `#rankUpdate`(榜单页纯图标按钮):`svgIcon('refresh',16)` → `svgIcon('download',16)`;CSS `#rankUpdate { padding-left/right: 11.5px }`(原 `.btn-icon` 9px→11.5px,总宽 35.3→40px ≈ +5px)
- `accUpdate`(账号列表「添加」「更新」并排按钮):`svgIcon('refresh',15)` → `svgIcon('download',15)} 更新`(保留文字,仅图标统一为下载)
- **不改动**:弹窗标题(`svgIcon('refresh',18)`)保持原样——用户只指定按钮
- **版本**:style.css ?v=20260903v→x、data-pages.js w→x(app.js 不动);同文件三处 bump 串行
- **CDP 验证**:JS=x;rankUpdate path 含 `M21 15v4...7 10 12 15 17 10...y1=15 y2=3` = download 图标 ✓;rankUpdate 宽 40px(+5)✓
## R36 榜单「下载按钮」靠近 tab(09-03 17:35)
- **需求**:用户反馈「下载按钮放到 tab 组件右边」「靠近 tab 组件 不是 筛选和搜索组件」
- **冲突点排查**:原来 rankUpdate 在 page-toolbar .toolbar-right;rank-toolbar.withFilters 控制整个 rank-toolbar(含 tab + 筛选)渲染——空态 toolbar(s,false) 时 rank-toolbar 不渲染;若简单把按钮移进 rank-toolbar 会丢失 R33 设计「空态也能看到更新按钮(首次抓取入口)」
- **解法**:**重构 toolbar() 函数**——tab 始终在 page-toolbar 渲染(含空态/错误态),rankUpdate 紧贴 tab 右侧;rank-toolbar 仅放筛选+翻页(withFilters 时)
- HTML:page-toolbar 子元素顺序 = 返回 / 标题 / `<div class="rank-tabs" style="margin-left:auto">` 三个 tab / `<button id="rankUpdate">⬇</button>`
- rank-tabs 用 `margin-left:auto` 推到右侧,rankUpdate 紧跟其后 → 视觉「"tab 组 + ⬇」紧贴
- rank-toolbar:只保留 .toolbar-right(赛道 select + 翻页),无 tab
- **CSS 复用**:`.page-toolbar .rank-tabs { border-bottom:none; margin-bottom:0; align-self:center }`(L603)+ `.page-toolbar .rank-tab`(L604 紧凑样式)已就绪,无需新增样式
- **验证**:
- CDP 实测:tab 在 page-toolbar ✓;btnInPageToolbar=true;filterExists=true(保留)
- 视觉截图:tab「账号周榜/视频热榜/点赞榜」+ ⬇ 在第一行右侧;筛选下拉+翻页在第二行
- **版本**:data-pages.js x→y(CSS 不动)
## R37 榜单下载按钮回 rank-toolbar + 去白底(09-03 17:40)
- **R36 偏差纠正**:用户反馈「你把 tab 和下载按钮 放下去,为啥总是喜欢把东西摆在标题哪一行呢」——R36 把 tab 提到 page-toolbar 错了,标题行应该只放 返回+标题
- **R37 正确布局**:
- page-toolbar:返回 + 标题「热点数据」(干净,无其他元素)
- rank-toolbar:**恒渲染**(含 tab + 下载按钮,保证空态/错误态也能看到更新入口),筛选+翻页仅 withFilters=true 时出现
- tab + ⬇ 紧贴:在 rank-tabs 容器内 rank-tabs flex:1 占满,tab 按钮 + ⬇ 排在最左(gap 4px),空白推到 ⬇ 之后容器尾
- **去白底**:用户「下载按钮去掉白底 只显示ICON」→ style.css `#rankUpdate { background: transparent; border-color: transparent }` + `#rankUpdate:hover` 同样覆盖 .btn:hover 默认主色边框;CDP 计算样式确认 bg=rgba(0,0,0,0) border=rgba(0,0,0,0)
- **验证**:
- DOM:page-toolbar 仅 返回+标题;rank-toolbar 含 rank-tabs(tab+⬇) + 筛选;⬇ inRankTabs=true 紧贴 tab「点赞榜」
- 视觉截图:tab 行下划线延续到 ⬇ 下方(rank-tabs border-bottom 自然延伸),⬇ 纯 icon 无边框,视觉与 tab 同组
- **版本**:data-pages.js y→z、style.css x→y(CSS 去白底+hover 覆盖;data-pages 移动 tab 到 rank-toolbar)
## R34 同步 dsh 副本计划
- dsh 副本 `C:\Users\maidou\.dsh\skills\short-video-script\`(独立副本,非软链)—— R34 改动 data-pages.js/app.js/style.css/index.html 同步评估后人工复制
## R38 首页榜单 tab 右侧加同款下载按钮(09-03 17:50)
- **需求**:用户「首页 榜单tab组件右边 相同位置也放下载按钮」——首页 rank-preview 的 rank-tabs(账号周榜/视频热榜/点赞榜)右侧加与榜单页 #rankUpdate 同款 ⬇ 按钮,行为完全一致(确认弹窗→后台任务重抓→冷却防重)
- **改动 3 文件**:
- `data-pages.js`:`window.DataPages` 导出新增 `updateRankingData`(L1811,供 app.js 首页跨文件调用;原榜单页绑定已在内)
- `app.js`:renderHome 首页 `.rank-preview .recent-head` 内 `.rank-tabs` 后插入 `<button class="btn btn-icon home-rank-update" id="homeRankUpdate" title="更新榜单数据…">${svgIcon('download',16,'currentColor')}</button>`(L330);renderPage 首页分支事件绑定 `window.DataPages && window.DataPages.updateRankingData(view, hUpd)`(L744-745)
- `style.css`:`.home-rank-update`(padding 11.5px 对齐 #rankUpdate + 去白底/边框透明)+ hover 覆盖 `.btn:hover` 默认主色边框
- **版本**:style.css ?v=20260903y→z、app.js v→w、data-pages.js z→aa(同文件三处 bump 串行)
- **CDP 冒烟** `tmp/cdp-r38-home-btn.mjs`(9225)15/15 PASS:三资源版本(z/w/aa)加载 ✓;homeRankUpdate 纯图标透明底(bg/border rgba(0,0,0,0))宽 35px ✓;**紧贴 tab 右侧 12px** ✓;与筛选控件同行无溢出(sameLineTools=true overflow=false)✓;点击 → 确认弹窗出现(title=更新榜单数据/上次更新 2026-08-24/取消+确认按钮)✓ 取消关闭 ✓
- **脚本坑**:`link[href$=".css"]` 匹配不上带 `?v=` query 的 href(以 z 结尾非 .css)→ 改 `link[rel="stylesheet"]` 后全绿
- **R35-R38 累计未推送**:本地 HEAD 领先 origin/main 2 commit(449d784 R35 / 1f147e8 R36)+ working tree R37/R38 待提交
## R39 网页改名 MCN创意雷达 + 首页榜单行垂直居中 + 下载按钮换 globe 图标浅色(09-03 18:00)
- **改名需求**:用户「将MCN工作台 网页上的名称改为 MCN创意雷达」——只改**网页显示层**(浏览器标题 title/面包屑 crumb-home/4 文件头注释/server.js 启动日志);**技能注册名「短视频工作台」绝不触碰**——`skills: ['短视频工作台']` 是工作台自身作为「短视频创作脚本技能」子技能挂载的标识,改名会导致 Skill 工具按名加载失败;工程目录名 `mcn-work-shop` 也保留
- **改名 6 文件**:
- `public/index.html` L6 `<title>MCN工作台</title>` → `<title>MCN创意雷达</title>`
- `public/app.js` L1 注释 + L732-733 面包屑两处(无 name span + 有 name a)+ L330 homeRankUpdate 按钮图标 download→globe
- `public/data-pages.js` L1 注释 + L528 rankUpdate + L795 accUpdate 三处 download→globe
- `public/style.css` L1 注释 + L430 #rankUpdate + L432 .home-rank-update 加 `color: var(--dim)`(浅色 icon,hover 自动继承 `.btn:hover` 变蓝)
- `server.js` L1 注释 + L974 启动日志 `MCN工作台已启动` → `MCN创意雷达已启动`
- `dsh-data.js` L1 注释
- **垂直居中修复**:
- 用户「首页 榜单的 下载按钮 和 右边的功能组件 都没有和 tab组件保持 垂直居中,现在是靠下的」
- 排查:`.rank-tabs` 全局 `align-self: stretch; margin-bottom: 10px`(下拉底线设计,底部 border 对齐列表)——当 `.rank-tabs` 作为 `.recent-head`(flex align-items:center)子项时,stretch + margin-bottom 使其被拉伸且下移,tab 文字相对兄弟偏上 **~5px**
- 修复:`style.css` L602 后新增首页局部覆盖 `.rank-preview .recent-head .rank-tabs { align-self: center; margin-bottom: 0; }`(CDP 实测修复后 tab 组中线/筛选中线/⬇ 中线偏差均 0px)
- **globe 图标(互联网语义替换文件下载)**:
- `ICON_PATHS` 新增 Lucide globe:`'<circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/>'`(圆+椭圆经线+水平纬线,与 download 箭头+托盘区分「从互联网抓取数据」)
- 三处按钮图标 download→globe:首页 `#homeRankUpdate`(`app.js` L330)/ 热点 `#rankUpdate`(`data-pages.js` L528)/ 账号列表 `#accUpdate`(`data-pages.js` L795,保留「更新」文字)
- **浅色 icon**:`#rankUpdate` + `.home-rank-update` 常态 `color: var(--dim)`(#6b7280 浅灰),hover 自动继承 `.btn:hover { color: var(--primary) }` 变蓝——无需额外 hover 规则
- **版本**:style.css z→aa、app.js w→x、data-pages.js aa→ab(同文件三处 bump 串行)
- **CDP 冒烟**(9225)拆 3 段独立连接(**`cdp-r39-brand.mjs` 完整脚本因 Page.reload+navigate 间歇 SIGTERM 拆为 a/b/c 三段单页最小脚本**),合计 **15/15 PASS**:
- 段 A `tmp/r39-a-home.mjs`(首页 #/):版本三绿(aa/x/ab)✓ / title=MCN创意雷达 ✓ / 面包屑=MCN创意雷达 ✓ / homeRankUpdate globe+浅色 rgb(107,114,128) ✓ / tab 组中线偏移=0px ✓ / 筛选中线偏移=0px ✓(9 项 PASS)
- 段 B `tmp/r39-b-ranking.mjs`(#/ranking):rankUpdate globe ✓ / 浅色 ✓ / 与最后 tab 中线偏移=0px ✓ / 距最后 tab 4px 紧贴 ✓ / 透明底 rgba(0,0,0,0) ✓(5 项 PASS)
- 段 C `tmp/r39-c-accounts.mjs`(#/accounts):accUpdate globe ✓ + 文字「更新」保留 ✓(1 项 PASS)
- **冒烟脚本坑**:
- **selector bug**:`document.querySelector('.rank-tabs .rank-tab:last-of-type')` 在 #/ranking 页**返回 null**——`.rank-tabs` 容器内是 4 个 `<button>` 平级(3 tab + #rankUpdate 自身),`:last-of-type` 匹配的是最后一个 button(即 #rankUpdate 自身),而 #rankUpdate 没有 class `.rank-tab` 故无匹配。修复:`document.querySelectorAll('.rank-tabs .rank-tab')` + `tabs[tabs.length-1]`。同样的坑也修进了权威脚本 `cdp-r39-brand.mjs`(L56)作为未来冒烟基线
- **SIGTERM 间歇**:单脚本含 Page.reload+Page.navigate+hash 多次切换时偶发被沙箱 SIGTERM 杀死 node 进程——规避=**拆段独立连接**,单脚本只做一件事;首页跳转 hash 用 location.hash=赋值(Runtime.evaluate)而非 Page.navigate
- **视觉目检** `tmp/shot-r39-brand.png`:顶部 brand `MCN创意雷达` ✓;首页榜单 tab 组(账号周榜/视频热榜/点赞榜)+ globe 按钮 + 筛选箭头完全水平对齐,globe 图标浅灰 ✓
- **R39 待推送**:本地 HEAD=28eba2a(R37-R38 已提交),working tree R39 6 文件改动 + 记忆日志 R39 节未提交;累计本地领先 origin/main **4 commit**(449d784 R35 / 1f147e8 R36 / 28eba2a R37-38 / R39 待提交)
## R40 弹窗 tab 切换闪烁根治 + 开始诊断文案 + tab 间 | 分隔(09-03 18:10)
- **用户反馈**:「为什么点击 脚本诊断 和 分镜提示词 整个弹窗页面都会闪一下。开始复盘 改为 开始诊断。脚本诊断 和 分镜提示词 切换按钮 之间加个 |」
- **闪烁根因**:R34 弹窗所有状态切换(tab/版本/源折叠/分镜上下版)都是 `mask.remove(); renderModal();` **整窗销毁重建**;而 renderModal async 在重建前必须 `await diagOf()`(网络请求 `/api/dsh/review-full`)→ 弹窗被删后要等接口返回才重新 append → 空窗几百 ms = 用户看到的「闪一下」
- **修复(架构级,openScriptModal 内重构)**:弹窗 DOM(mask)生命周期内**不再移除**,仅就地替换受影响列:
- `curOf()` / `verCtrl()` / `sideHeadHtml()` / `srcToggleHtml()` / `srcSecHtml()` / `aiSecHtml()` 抽成独立 HTML 工厂
- `sideContent(cur)`:右侧列内容计算(**stab=diag 才请求 review-full**——原实现无论什么 tab 都查,浪费);空态按钮文案「开始复盘」→「**开始诊断**」
- `patchSide(mask)`:就地刷新右侧列(tab 切换/分镜上下版)——active 即时切换 + body「加载中…」→ await sideContent → 填充;`sideToken` 递增防连点竞态、`mask.isConnected` 防已关闭后写入
- `patchAll(mask)`:就地刷新 AI 列+右侧列(版本上/下一版)
- `bindAll/bindSide/bindScrollSync`:动态节点绑定分层——mask 外壳 data-x/背景关闭只绑一次;stack 内节点每次重建后重绑(旧节点随 innerHTML 替换销毁,无重复监听)
- 源折叠 `[data-src-toggle]` 改**纯 CSS class toggle**(不再重建)
- **tab 间 `|` 分隔**:sideHeadHtml 两按钮间插 `<span class="rw-side-sep">|</span>`;CSS `.rw-side-sep { color: var(--border); font-size: 14px; user-select:none }`
- **版本**:data-pages.js ab→ac、style.css aa→ab(app.js 不动)
- **CDP 冒烟** `tmp/cdp-r40-modal.mjs` **16/16 PASS**:| 分隔在两 tab 之间 ✓ / 默认 tab=diag ✓ / 按钮「开始诊断」且零「开始复盘」残留(源码级)✓ / **切分镜、切回诊断、版本下一版全程 mask 同一节点未重建(不闪)** ✓ / 分镜内容已填充 ✓
- **弹窗行为定版**:tab 切换/分镜翻版/版本翻版/源折叠全部就地刷新 → 无空窗闪烁;仅初次打开 await 数据齐后一次 append
## R41 弹窗右侧面板可收起(只展示 AI 脚本)(09-03 18:25)
- **用户反馈**:「添加功能 可以收起 脚本复盘 | 分镜提示词 内容板块,只展示AI脚本」
- **设计**:右侧「脚本诊断|分镜提示词」列可整体收起 → display:none → AI 列 flex:1 自动占满内容区(源列默认收起时即「只展示 AI 脚本」)
- 状态 `showSide`(默认 true);右侧列 rw-sec 挂 `data-side-sec` + 按需 `rw-sec-hidden`(复用 R34 源列收起类)
- **收起钮位置关键决策**:放 **AI 列 head 最右**(`margin-left:auto`)而非右列自身 head——右列收起后自身头部不可见,展开入口必须常驻 AI 列;`.rw-side-toggle`(chevrons-right=收起/chevrons-left=展开,收起态 `side-off` 高亮提示可点开)
- app.js ICON_PATHS 新增 `chevrons-right`/`chevrons-left`(Lucide 双箭头);改 app.js 后版本也要 bump
- **代码**:data-pages.js(showSide 状态、sideToggleHtml、bindAll 内 data-side-toggle 绑定、renderModal 初渲染按 showSide 加 class);style.css `.rw-side-toggle`(margin-left:auto + hover 蓝 + side-off 高亮)
- **版本**:style.css ab→ac、data-pages.js ac→ad
- **CDP 冒烟** `tmp/cdp-r41-side.mjs` **17/17 PASS**(两轮):收起后右列 display:none、仅 AI 列可见、**AI 宽=stack 宽 100%**、收起钮切展开态高亮 ✓ / 展开恢复 ✓ / 收起过程与展开过程 mask 未重建 ✓ / **收起态下切分镜 tab 正常**、展开后停在分镜 ✓
- **冒烟断言口径坑(3 FAIL 全为此)**:**源列默认收起 → 打开弹窗初始可见列=2(AI+右侧)不是 3**;AI 宽度占比基准应取 `.rw-stack` 内容宽而非 `.rw-modal` 宽(modal 有 padding 26px×2,占 modal 宽 95% 即已满)
- **回归**:R40 冒烟版本断言更新(ab/ac→ac/ad)后复跑 16/16 全绿——R41 未破坏 R40 就地刷新架构
- **R40-R41 待提交**:data-pages.js/style.css/app.js/index.html + 记忆日志本节;本地 HEAD=03de8be(R39 已 push origin/main)
## R42 视频详情返回语义(09-03 定位中,未落地)
- **需求**:「账号详情 点击 视频列表 再点击列表中视频标题 打开视频详情页,点击返回,回到账号详情tab,而不是视频列表tab」
- **代码事实**:账号详情 tab(info=账号信息/persona=视频列表/analysis=数据分析)纯 JS 切换**不写 hash**;视频标题 `<a href="#/video/:id">` 标准 hash 导航;bindBack=history.back() → 返回前一 hash → renderAccountDetail 重新整页渲染(tab 闭包全新=info)
- **落点规律**:返回落哪个 tab 取决于账号详情历史条目的 hash——仅 `#/account/:id` → 落「账号信息」;若进入时带 `/persona` 第三段(测试深链习惯 `#/account/1629/persona`)→ 落「视频列表」
- **方案候选**:A=tab 切换同步 replaceState 写第三段 hash(保持离开位置);B=从视频详情返回强制回账号信息。语义待用户澄清后再实施
## R43 网页改名 MCN热点雷达(09-03 19:20)
- **需求**:「MCN创意雷达 改为 MCN热点雷达」——纯显示层文字替换(R39 改名同款范围),技能注册名「短视频工作台」/目录名 mcn-work-shop 不动
- **改动 6 文件**:index.html `<title>`、app.js L1 注释+面包屑 2 处(无 name span 分支 + 有 name a 分支)、data-pages.js L1 注释、style.css L1 注释、server.js L1 注释+L974 启动日志、dsh-data.js L1 注释
- **版本**:app.js 20260903x→y(面包屑渲染变化;**顺带修复 R41 改 ICON_PATHS 后 app.js 未 bump 的缓存隐患**);style.css ac / data-pages.js ad 仅注释变更不 bump
- **CDP 冒烟** `tmp/r43-brand.mjs`(9225)**8/8 PASS**:三资源版本(ac/y/ad)/ 标题=MCN热点雷达 / 首页面包屑无分隔=热点雷达 / #/accounts 面包屑 前缀+当前 两段
- **坑**:首次运行瞬态退出码 23 无输出(重跑即过);页面为改动前旧加载需先 Page.navigate ignoreCache 强刷再断言;server.js 纯文字改动无需重启(文件服务即时生效,启动日志仅下次 boot 显示)
- **commit 52a5058 已 push origin/main**(dfef295..52a5058)
## R42 视频详情返回语义 落地(09-03 19:30)
- **需求澄清结果**(用户选「保持离开前状态」):从哪个 tab 点进视频,返回就回到哪个 tab;视频列表翻页位置也保留
- **实现**:`renderAccountDetail` 内新增 `syncHash()` 函数 = `history.replaceState` 把当前 tab + persona 页码同步进 hash 第三/四段:`#/account/:id[/<tab>[/<page>]]`;tab 点击与 bindPager 回调各加一行 `syncHash()`(不污染历史记录)
- **代码 3 处串行 Edit**(data-pages.js 同文件):①L917-920 解析块增加第四段 page 解析 + `syncHash` 函数定义;②L1029-1033 tab 点击 handler 加 `syncHash()`;③L1034 bindPager 回调加 `syncHash()`
- **hash 规则**:info tab → 裸 `#/account/:id`;persona/analysis → `#/account/:id/<tab>`;persona 翻第2页起 → `#/account/:id/persona/<page>`(≥1 才写);info 切回时 hash 也清回裸路径
- **版本**:data-pages.js `20260903ad → ae`;app.js/style.css 不动
- **CDP 冒烟** `tmp/r42-back-tab.mjs`(9225)**13/13 PASS**:动态取首账号 id=2 → 默认 info → 切 persona hash 同步 → 翻第2页 hash 带 `/persona/2`(pager「第 2/5 页」)→ 点第一条视频进详情 → 点「←」→ 返回 `#/account/2/persona/2`、活动 tab 视频列表、pager 第2页保留 → 切回 info hash 回裸
- **视觉留档**:`tmp/shot-r42-persona2.png`(深链 `#/account/2/persona/2` 直开=视频列表第2页完整还原)
- **坑**:Page.navigate 多次 SIGTERM——截图脚本改用纯 hash 切换避免;首次冒烟需先 Page.navigate 强刷使新版 data-pages 入 DOM 再断言
- **commit 049d37a 已 push origin/main**(52a5058..049d37a)
## R44 账号详情信息字段跨行对齐(09-03 19:10)
- **需求**:「账号详情中 抖音号 和 赛道 内容的宽度保持一致,现在抖音号内容有长有短 导致作品数和AI制作错位了」
- **根因**:账号信息卡用两个独立 `.info-row` flex 容器(行1=抖音号/作品数/获取视频,行2=赛道/AI制作/粉丝/获赞),各行按内容宽度左排 + gap 80px——抖音号长则「作品数」被顶到右侧,而赛道短「AI制作」靠左,跨行第 2 列 x 起点不一致 = 视觉错位
- **修复**:套用 09-02 视频详情已验证的同款 grid 方案——`panel` 改单容器 `.account-info .account-grid`,**grid-template-columns: repeat(4, minmax(min-content, max-content)) + grid-template-areas: 'a b c .' 'd e f g' 'h h h h'** 列轨道跨行共享(首列=抖音号↔赛道同宽、b列=作品数↔AI制作严格对齐);infoGrid 增第 5 参 area(内联 grid-area:a~h);wide「账号定位」= h 区
- **改动**:data-pages.js(infoGrid 签名 + panel 段);style.css 新增 `.account-info .account-grid` 2 行(areas 模板 + item min-width:0)
- **版本**:style.css ac→ad、data-pages.js ae→af
- **CDP 冒烟** `tmp/r44-align.mjs`(9225)**10/10 PASS**(账号 2 Ricardo1999,抖音号英文长 ID):account-grid 8 字段 ✓ / 抖音号.left=赛道.left=40.7 ✓ / 作品数.left=AI制作.left=353.2 ✓ / 获取视频.left=粉丝.left=665.7 ✓ / 首列格宽 抖音号=赛道=232.5px ✓ / 第2列格宽一致 ✓ / 字段内容非空 ✓
- **坑**:冒烟首次 FAIL 全因页面停在旧资源(ac/ae)——须先 Page.navigate ignoreCache 强刷新版再断言(页面 hash 直跳不换 index.html)
- **commit 8da5981 已 push origin/main**(52a5058..8da5981)
## R45 账号详情信息卡属性宽度对齐视频详情(09-03 20:30)
- **需求演进**:
- R45-1「可以这样改 但是属性之间间隔可以窄一些 现在宽了些」(对 R44 反馈)
- R45-2 第一轮误解为 gap 80→40 + 账号定位移出网格(用户否决「没让你改这么窄」)
- R45-3「参考视频详情的属性宽度」(明确指令)→ 终版 = 账号定位移出网格(核心)+ gap **80px 与 .video-grid 一致**(不能再砍)
- **根因再确认**(R44 误判的二次根因):用户感知「间隔宽」主要不是 gap 数值大,而是「账号定位」长段落的 max-content 留在 grid 内 h h h h 区,把 4 列轨道**全部撑成等宽 232.5px**——每格右侧大片留白叠加 80px gap = 视觉间隔过宽;移出 wide item 后列贴内容收缩(抖音号列 108.9、作品数列 42),gap 80 即可恢复视频详情观感
- **实现(终版)**:
- `data-pages.js` L1013:`panel` 拆两段——`.account-grid` 内 7 infoGrid(a~g,删 h),账号定位改独立 `${infoGrid('账号定位', contentHtml, true, true)}`(无 area 参)作为 .account-info 直接子项平级输出
- `style.css` L519-531:`.account-info .account-grid` 去 `'h h h h'` 区行(保留 `'a b c .' 'd e f g'`),**gap 80px 保持与 .video-grid 同款**;新增 `.account-info > .info-item { margin-top: 12px }` 给账号定位整行纵向间距(`.account-info > .info-item` 子选择器精准命中网格外的直接子项,不影响网格内 7 个)
- **版本**:style.css ad→af(直跳终版)、data-pages af→ag、app.js 不动
- **CDP 冒烟** `tmp/r45-gap.mjs`(9225)**14/14 PASS**(账号 2 Ricardo1999):grid 7 字段 ✓ / 账号定位独立整行直接子项 wideN=1 ✓ / 抖音号.left=赛道.left=40.7 ✓ / 作品数.left=AI制作.left=229.5 ✓ / columnGap=80px ✓ / 实算 79.9(ws.left - dy.right)✓ / maxColW=108.9(旧 232.5→贴内容收缩)✓ / 抖音号列 108.9 > 作品数列 42 ✓ / 字段非空(Ricardo1999↗、生活vlog、148、否)✓ / 账号定位 wide=1170 占满卡片 1203.3 ✓ / 位于网格下方 gridBottom=305.7 wideTop=317.7 ✓
- **视觉留档**:`tmp/shot-r45-gap.png`——7 字段列贴内容、gap 80 同款、账号定位独立整行不再被压缩成等宽列
- **坑**:
① **同文件并行 Edit 覆盖陷阱**:实测 index.html 两个 Edit 并行(ad→ae 与 af→ag)时,data-pages 的 Edit 覆盖了 css 版本号变更 → 最终直跳终版 af 规避。教训=同一文件多 Edit 必须串行或合并为一次
② CDP 冒烟须**无条件 Page.navigate ignoreCache 强刷新版再断言**(hash 直跳不换 index.html,旧 CSS 残留)——本次脚本改默认强刷后再跑即 14/14 通过
- **commit 51bf049 已 push origin/main**(8da5981..51bf049)
## R46/R47 脚本诊断维度术语改名(09-03 21:40)
- **需求链**:R46「钩子设置→爆款开场、共鸣和共情→创意和爆点(排在设定承接前面)」;R47 紧随「创意和爆点→创意看点」(术语二次打磨定稿)
- **关键认知——维度名是「数据 key」非纯显示 label**:诊断分数存 dims_json(key=维度名),由 AI 按 mcn-script-review 技能(SKILL.md 表格维度定义)输出。UI 数组(DIMS/DIMS_ALL/DIAG_DIMS)元素同时充当展示名与取值 key——直接改名会让历史复盘分数全部变「-」
- **方案 = 改名 + 旧 key 别名兼容**(data-pages.js):
- 三处数组改新名+新序:`['创意看点','设定承接','框架节奏','爆款开场','叙事逻辑','极致事件',…]`(创意看点置首、爆款开场原地)
- 全局 `DIAG_KEY_ALIAS = { '爆款开场': '钩子设置', '创意看点': '共鸣和共情' }` + `diagDimVal(dims,k)` helper:新 key 缺失时读旧 key → 历史分数继续展示
- 4 处取值统一换 diagDimVal(L1477 列表 / L1552 复盘详情 scoreBar / L1611 完整报告 scoreBar / L1708 诊断组件 scoreBar)
- **版本**:R46 data-pages ag→ai、R47 ai→aj(内容变更必 bump,教训:R46 修复 helper 后忘 bump 导致 navigate 命中缓存旧 bug 版,冒烟持续 FAIL)
- **CDP 冒烟** `tmp/r46-dim-rename.mjs`(9/9)`tmp/r47-dim-rename.mjs`(9/9,sed 复制改词):表头序列=创意看点/设定承接/框架节奏/爆款开场/叙事逻辑/极致事件/其他/总分 ✓ / 历史行 创意看点=93、爆款开场=90(旧 key 兼容)✓ / 详情弹窗评分条顺序 + 分值 ✓
- **坑(重要)**:`Edit replace_all` 会误伤被替换模式自身——R46 把 helper 定义内 `const v = dims[k];` 也替换成 `diagDimVal(dims,k)` 自递归 → 页面 Maximum call stack size exceeded 崩溃;修复后 grep diagDimVal 全量核对引用点才干净
- **commit e296b60(R46)/ d1806a0(R47)已 push origin/main**
- **遗留待用户确认**:技能侧(源 `subskills/mcn-script-review` + dsh 副本 `script-review`)SKILL.md/脚本复盘流程.md 维度名仍旧名(钩子设置/共鸣和共情)——AI 复盘仍输出旧 key,UI 靠别名兼容显示正常;若要 AI 感知新术语语义须同步技能侧(修改技能文件走「方案→确认→执行→同步 dsh 副本」流程)
## R46/R47 技能侧同步收尾(09-03 22:20,用户经确认选「改名+重排」)
- **mcn-script-review v1.4**(源 + dsh script-review 副本,两文件 diff 一致):
- SKILL.md:frontmatter v1.3→1.4/updated 09-03/last_change 记录术语变更;维度清单重排——创意看点(原共鸣和共情检查点原样)置首,设定承接/框架节奏/爆款开场(原钩子设置)/叙事逻辑/极致事件顺延
- references/脚本复盘流程.md:L39 顺序说明、表格维度小节整块重排(维度1=创意看点…维度6=极致事件,追加 7-10 不动)、独立分析报告模板 6 行表、汇总行「各维得分」、对比分析表 6 行,全部新名+新序
- 检查项细分词(共鸣类型命中/具象场景检验/自嗨检测/3问自检)保留不改(用户只改维度名,评分细则不动)
- **发现并补漏**:dsh script-review SKILL.md 缺「与相关技能的关系」末行(MCN工作台入口说明,09-02 执行方式判定节新增时漏同步)——本次顺带补齐
- **核验**:源 vs dsh strip CR 后 diff 全一致;旧维度名 grep 仅剩 last_change 历史记录(正常)
- **行尾事实**:源 md 工作区 CRLF、dsh 副本 LF——diff 前须 `tr -d '\r'` 归一,否则整文件误报差异
- **commit dd80d5d 已 push origin/main**(d1806a0..dd80d5d,含 dd499d7 memory 一并推送)
## R48 账号/视频详情属性内容统一宽度 140px(19:35-20:20 定稿)
- **用户真实意图(两次纠正后定稿)**:①「间隔不一样」≠行高≠列间 gap——是**各属性内容宽度参差**(grid `minmax(min-content,max-content)` 列贴内容:抖音号列 75.7~108.9px / 数字列 42px / 粉丝~70px / 获赞~80px,gap 其实恒 80px,是列宽不一造成视觉间隔差);②方案不是「max-width 上限」(只压抖音号列,其余列仍参差)而是**所有属性值固定统一 width**
- **终版落码(账号详情 + 视频详情同款)**:`.account-grid/.video-grid` 内 `.info-item { width: 140px }`(先 80 后用户改 140);`gap: 10px 80px → 10px 0`(去掉横向间隔,用户:「内容统一宽度不就行了,先设置80PX,不要其他间隔」→ 后改 140px);`.info-item .info-value { overflow:hidden; text-overflow:ellipsis; white-space:nowrap }` 统一省略号
- **info-wide 例外**:视频详情「标签」是 `.info-item.info-wide { grid-column:1/-1; width:auto }` 占整行不受限宽保持换行;省略号规则用 `:not(.info-wide)` 排除;账号定位整行在 grid 外天然不受影响
- **连带清理**:视频详情原 `vid-limited` 独立 max-width 220 被统一 140 覆盖→删冗余 CSS 规则(JS title 提示保留,hover 看全量);抖音号链接 title 改为「{完整抖音号} · 点击打开抖音主页」(省略号下 hover 看全量)
- **版本**:style.css af→ai(账号)→aj(视频详情);data-pages.js aj→ak(title 改动)
- **实测**:CDP 9225 账号页 7 字段、视频页 8 字段全 140px 等宽 PASS;colGap=0
- **commit**:c58f4ad(账号详情)+ 3f85853(视频详情),**⚠️ 未 push(SSH 222 Connection closed,待网络恢复重试)**
- **tmp 清理(20:18)**:60 个冒烟脚本/截图/probe 全清空(tmp/ 已被 .gitignore 忽略不入库);仅剩 `cdp-profile-r28`(66MB)被 9225 调试浏览器占用无法删(Device busy),关浏览器后可清
- **坑**:find -exec rm -rf 碰到被占用目录会卡住被 SIGTERM 中断、后续条目没删完→需 `! -name '被占用目录'` 排除后分批删
## R49 榜单三 tab 行高对齐账号周榜(22:20-22:30)
- **诉求**:热点数据首页预览 + 功能页(#/ranking) 的榜单列表,三个 tab(账号周榜/视频热榜/点赞榜)每行高度统一以账号周榜为基准
- **根因**:账号周榜多「功能」列(含「查看/关注」按钮 .btn-sm padding 3px+边框),按钮把行撑高——功能页 42px / 首页 40px;热榜/点赞榜无按钮纯文本仅 34.7px / 30.7px,切 tab 行高跳动
- **落码**:功能页 `.table.table-rank td { height: 42px }`(全局 * box-sizing:border-box,height=总高);首页 `.rank-preview-list .rank-row:not(.rank-head) { min-height: 40px }`(排除表头 rank-head)
- **实测**:功能页三 tab 全 42px、首页三 tab 全 40px PASS(CDP 9225)
- **commit a88f2dc**(含 memory 追加一并入库;tmp/r49-measure.mjs 在 gitignore 不入库)
## R50 AI脚本弹窗默认态:仅展开AI脚本、收起复盘/分镜、默认最新版(22:30-22:50)
- **诉求**:「AI脚本的弹窗默认展开AI脚本,不显示复盘和分镜,AI脚本默认展示最新的版本」
- **唯一改动**:`openScriptModal` L1665 `showSide=true → false`(R41 已支持 `rw-sec-hidden` + AI 列 `flex:1` 自动占满;`sideContent` 照常预取,展开钮点击后内容即时可见不死)
- **verIdx 不改的判定(关键)**:AI脚本入口(renderRewrites `data-detail`)只传 videoId → verIdx 天然回落 0 = 最新(后端 `getVideoScript` 已 `ORDER BY id DESC`);若强行简化 `verIdx=0` 会破坏脚本诊断页 `data-open` 按 rewriteId 定位具体版本的导航(L1506)——「默认最新」仅对未指定版本入口成立
- **版本**:data-pages.js ?v=ak → al(style.css 不动)
- **实测**:CDP 9225 冒烟 7/7 PASS(视频 313 三版本 id 35/32/27):T1 弹窗开 / T2 AI列展开可见 / T3 右侧面板 rw-sec-hidden / T4 源收起 / T5 版本 1/3 / T6 内容=rewrites[0](id=35《妈妈失声第一天…》)/ T7 展开钮可恢复右侧面板
- **commit 2562ddf 已 push origin/main**(876fdbb..2562ddf)
- **tmp 已清空**:cdp-profile-r28(旧占用 66MB)+ cdp-profile-r50 均已删除;教训=Chrome 杀监听进程后须再按 CommandLine 匹配 `cdp-profile-r*` 清残留子进程才能释放 profile 锁(否则 rm 卡死 SIGTERM)