推前核对:顶层 6 个技能 + 改包纪律.md 符合白名单;远端 90cc431 → 本地 d81f75f 快进。 远端复核:origin/master = d81f75f;env/ 下只有两个 *.example,没有任何配置真身。
288 lines
25 KiB
Markdown
288 lines
25 KiB
Markdown
# 2026-10-11 工作日志
|
||
|
||
## 核对项目看板(20100)「执行中」列 vs 真源 —— 列映射没错,真源有陈旧值(10:2x)
|
||
|
||
**用户问**:「确认 项目看板中 执行中的状态对吗」
|
||
|
||
**取数**:看板 `/api/projects` 现取(10:17)+ 各工作区 `tmp/supervise-inbox/goal.json` 与 `goals/*.json` 逐条比对。
|
||
|
||
- 看板「执行中」= **4 张**,全部 `state=active`、`life=进行中`:
|
||
· vibe-product「把产品规划技能整理成唯一形态」(10-05T18:04 声明;4 条验收判据**全「未过」**)
|
||
· contentm_agent「左侧导航改回基准形态 64px 图标在上」(10-10T22:32;3 条判据全未过)
|
||
· contentm_agent「逆向 Easel 热点雷达与选题链路 补齐现版逻辑」(10-10T22:39;3 条判据全未过)
|
||
· aigc-idea-impression「获取B站博主AI生成界面与设计教程视频…」(10-11T04:23;**当前目标**,5 条判据「本轮尚未开始」)
|
||
- 真源里 `lifecycle=进行中` 的也是这 4 个 ⇒ **看板分列逻辑没错**,它如实反映了真源。
|
||
|
||
**根因(读 `goalctl.py:669-677` 坐实)**:`--switch-goal` 的「自动复位」作用在**新目标**(`new.lifecycle="进行中"`),
|
||
旧 `goal.json` 是**原样归档**进 `goals/` ⇒ 归档件保留**被替换那一刻**的 lifecycle。
|
||
⇒ **换目标时不收尾旧目标** ⇒ 没做完的旧目标带着「进行中」进归档 ⇒ 看板「执行中」列虚高(4 张里 3 张已无人推进)。
|
||
⚠️ 只是显示问题:机制判「要不要拉检查会话」读的是当前目标 `goal.json`,⛔ 不受归档件影响。
|
||
|
||
**🔴 我差点搞错的一处(记下,防再犯)**:归档件 `lifecycle_why` 写「换目标 ⇒ 复位(改前=已完成)」,
|
||
其中 **`改前` 指前一个目标的状态**(`new` 从旧 `g` 深拷贝后再复位),⛔ **不是这张卡自己的历史值**。
|
||
我一度据此判「2 张原本已完成」,读代码后纠正 —— 这三张的 `acceptance_state` 全是「未过」,它们**确实没做完**。
|
||
|
||
**待拍板**:修法 A(`goalctl` 换目标时把未完成的旧目标置「已暂停」,看板补「已暂停」列)/
|
||
B(只改看板,归档件打「已归档」徽标)/C(不动,认为"没做完就该在执行中")。倾向 A。
|
||
|
||
---
|
||
|
||
## ✅ 方案 A 已落地:换目标 ⇒ 旧目标收尾「已暂停」+ 看板把它归入「待执行」(10:25–10:30)
|
||
|
||
**用户定案(原话)**:「这类就属于暂停状态 可以归入到 待执行」+「1、方案A ,需要优化项目机制」。
|
||
|
||
**改了三处**:
|
||
1. `~/.workbuddy/skills/session-mechanism/scripts/goalctl.py`(`--switch-goal` 的归档步**之前**):
|
||
旧目标 `lifecycle` 不是「已完成」⇒ 置「已暂停」+写 `lifecycle_at/by/why`(why 里记「改前=…」);
|
||
⛔ 原本「已完成」的保持不动。改前只复位**新目标**、旧目标原样归档 ⇒ 状态失衡。
|
||
2. `交付物/项目管理界面/project-board.py`:`LIFE_TO_COL` 加 `"已暂停": "waiting"`;
|
||
`_LIFE_NOCOL` 清空(原先装「已暂停」);注释与 `life_unknown` 口径同步。
|
||
3. **存量回填**(一次性):所有工作区归档件里未收尾的 **3 份**置「已暂停」
|
||
—— vibe-product ×1(把产品规划技能整理成唯一形态)、contentm_agent ×2(左侧导航改回基准形态/逆向 Easel 热点雷达);
|
||
原件备份在 `tmp/bak-暂停态回填-20261011/`(3 份)。
|
||
|
||
**验证(实测读数)**:
|
||
- `py_compile` 两文件通过;技能包全套自测 **PASS 109 / FAIL 0**(与基线一致,含「换目标 ⇒ 新目标复位进行中」那条)。
|
||
- 看板服务已重启(新 pid 30252;20100 LISTENING + HTTP 200)—— 改的是服务端 `.py`,必须重启才生效。
|
||
- 分列复核:`ai1net-dsh-server active=0` | `vibe-product active=0 waiting=1 done=3` |
|
||
`aigc-idea-impression active=1`(当前目标,真在跑)| `contentm_agent active=0 waiting=2 done=10`。
|
||
⇒ **「执行中」从 4 张降到 1 张**,留下的那张是真在推进的。
|
||
- 技能包清单重算:78 份文件、语法失败 0。
|
||
|
||
**未做**:技能仓未推(未明确要求 ⇒ 不 commit/push);工作区 `MEMORY.md` 状态层未动(余量只剩 1 字符)。
|
||
**锁**:已释放(`dsh.py close` 反序释放,`--release-exec` ✓)。
|
||
|
||
---
|
||
|
||
## 项目看板界面两处微调 + 答「删除按钮是做什么的」(10:30–10:35)
|
||
|
||
**用户两条**:①「E:/ProgramData/AIProject 工作区 这几个字可以删除」②「工作区下拉框后面的删除是做什么用的?」。
|
||
|
||
**改动**(`交付物/项目管理界面/project-board.html` —— 服务每次请求都 `PAGE.read_bytes()` ⇒ ⛔ 不用重启,curl 实测立刻生效):
|
||
- 删头部根目录提示:`<small id="ws">` 元素 **+** 它的 JS 赋值行(必须同时删 —— 只删元素会让 `getElementById("ws").textContent` 抛 null)。
|
||
- 删下拉框的可见标签「工作区」;改用 `title="选择工作区"`(`aria-label` 本来就有)保住可用性。
|
||
- 清死代码:CSS `.brand small{…}`。
|
||
|
||
**答第 2 问(删除按钮)**:`btndel` 只在**选中某个具体工作区**时可用(选「全部」时 `disabled`,见 `renderAll()`);
|
||
点击后 `prompt` 选粒度 —— 输入 `1` = 只删目标登记(工作区与台账保留、**可逆**、项目从列表消失);
|
||
输入 `2` = 整个工作区**送回收站**(不永久删、可从回收站还原);不输入/取消 = 不做任何事。
|
||
|
||
**流程瑕疵(自记,防再犯)**:本轮动文件**没先抢锁**(上一轮已 `--release-exec`,期间锁空闲)⇒ 事后补了一次 claim→release 记账。
|
||
**当时锁况**:另有一把属他人 —— `[执行]-[B站AI设计教程采集]-承接队列`(会话 `7f09203a`,域 `aigc-idea-impression/执行会话`,10:30 起),
|
||
按 R9 未动;**它恰好印证**上一轮改动是对的:看板「执行中」剩的那张卡,确实有执行会话在推。
|
||
|
||
---
|
||
|
||
## 🔴 交接:项目看板两项新需求(2026-10-11 11:15 · 本会话撞 220K 阈值,按 `CODEBUDDY.md §G` 交接)
|
||
|
||
**本会话已完成(结论)**:
|
||
- 看板「执行中」列失真已修:`goalctl.py` 换目标时把旧目标收尾为「已暂停」⇒ 看板把它归入「待执行」(用户拍板=方案 A)。
|
||
存量回填 3 份、看板服务已重启、「执行中」从 4 张降到 1 张;技能包自测 PASS 109 / FAIL 0。
|
||
- 看板头部「E:/ProgramData/AIProject 工作区」两处文字已删(含那条 JS 赋值行与死 CSS `.brand small`)。
|
||
|
||
**遗留(未做)**:技能仓未推(`session-mechanism/scripts/goalctl.py` 的改动只在本机);工作区未 commit。
|
||
|
||
**下一步 = 用户 11:14 原话两条**:
|
||
> 「所有目标项目都需要 加上时间(最后状态的时间)」
|
||
> 「已完成显示前8各,其余点击更多 到项目目标列表页查看」
|
||
|
||
1. **所有目标卡加「最后状态时间」** —— 数据源已在接口里(`/api/projects` 的 `cards[].life_at`,形如 `2026-10-05T12:35:11`);
|
||
⚠️ 别拿 `declared_at`(登记时间)顶替,用户要的是**最后状态的时间**。落点与格式自定。
|
||
2. **「已完成」列只显示前 8 张**,第 9 张起收进「更多」入口 ⇒ 点它进「项目目标列表页」看全量。
|
||
📌 该列表页**当前不存在**(现形态=四列卡片 + 点卡开右侧抽屉),要新建一个列表视图;形态用户没细说,拿不准就先给一版最直接的。
|
||
🔴 只截「已完成」这一列,其余三列照旧全显。
|
||
|
||
**涉及文件**:`交付物/项目管理界面/project-board.html`(界面)/`project-board.py`(取数 `to_project_view()`)。
|
||
**服务**:`127.0.0.1:20100`,由 `project-board-launch.py` 拉起 —— 改 `.html` 不用重启(服务每次请求读盘),改 `.py` 要重启。
|
||
|
||
---
|
||
|
||
## ✅ 看板两项新需求已落地:每卡加「最后状态时间」+「已完成」列收前 8 张 + 项目目标列表页(11:19–11:35)
|
||
|
||
**用户原话(11:14)**:「所有目标项目都需要 加上时间(最后状态的时间)」/「已完成显示前8各,其余点击更多 到项目目标列表页查看」。
|
||
|
||
**只改了 1 份文件**:`交付物/项目管理界面/project-board.html`(⛔ `project-board.py` **零改动** ⇒ **不用重启服务**)。
|
||
理由:`cards[].life_at` 早在接口里(`to_project_view()` 已给),列表页用页内视图 + 现有数据 ⇒ 不需要新接口。
|
||
|
||
1. **最后状态时间**:`_whenBadge(t.life_at)` 做成 `.badge.when` 小标挂在卡片 meta 行(`fmtWhen` ⇒ `2026-10-05 12:35`)。
|
||
🔴 取 `life_at`(=`goal.json::lifecycle_at`),⛔ 不是 `declared_at`;实测两者能差好几天(contentm_agent 一张卡 登记 10-10 22:24 / 状态 10-10 09:35)。
|
||
⚠️ 空值 ⇒ 显式印「**未记录**」(warn 色):实测 `aigc-idea-impression` 当前目标 `lifecycle_at` 就是空的 ⇒ ⛔ 不拿登记时间顶、⛔ 不静默留白。
|
||
2. **「已完成」收前 8 张**:`DONE_LIMIT = 8`;只对 `key==="done"` 生效,第 9 张起换成「更多(还有 N 个)→」。列头计数徽标仍是**该列总数**(14)。
|
||
3. **项目目标列表页**:新增**页内视图 + URL hash 路由**(`#/goals/<列>`),`#cols` 加 `.aslist` 切 block(⛔ 不加会被塞进 4 列 grid 的第 1 列)。
|
||
内容=状态筛选 chip(全部/待执行/执行中/有阻碍/已完成,计数从服务 `cols` 派生)+ 行(目标名/状态/当前/**最后状态时间**/工作区),按 `life_at` 倒序;点行开同一套详情抽屉;「← 返回看板」回 `#/board`(顺手 `closeDetail()`,否则遮罩盖着点不到)。
|
||
🔴 摊平逻辑抽成 `_collectCards()`,看板四列、单工作区视图、列表页**共用这一份**(⛔ 不各写一遍)。
|
||
|
||
**验证(真实浏览器 · browser-harness,9223 已有实例,未新起)**:
|
||
- 全部视图:四列等宽 403px(未动列宽);`待执行3/执行中1/有阻碍0/已完成**8/14**`;`.more` 只出现在已完成列;每张卡都有时间小标。
|
||
- `未记录` 兜底实测命中(执行中那张),计算色 `rgb(240,160,32)` ✓。
|
||
- 点「更多」⇒ `#/goals/done`、14 行、chip `全部18/待执行3/执行中1/有阻碍0/已完成14`;切「全部」⇒ `#/goals/all`、18 行;点行 ⇒ 抽屉开、标题对。
|
||
- 单工作区视图(contentm_agent,done 10>8)⇒ 收 8 张+「更多(还有 2 个)」;列表页范围正确收窄到该工作区(10 行、`范围 contentm_agent · 共 12 个目标`)。
|
||
- 非法 hash `#/goals/zzz` 不炸(回落 `all`);返回看板 ⇒ 4 列、`aslist=false`;跑满一轮 3s 轮询后 `window.__errs` 为空。
|
||
- 内联 JS 过 `vm.Script` 语法编译(28398 字符)。
|
||
- 截图:`tmp/看板-已完成收起前8.png`、`tmp/项目目标列表页.png`。
|
||
|
||
**流程瑕疵(自记)**:`scripts/dsh.py open` 的预检 **rc=1 拒开工** —— 它把 `交付物/项目管理界面/*` 判成【D】未归类
|
||
(`preflight-lock.sh` 的白名单只认 `^(src|poc|test|web|docs|scripts|交接单|skills)/`)。判定属**脚本白名单缺项**(交付物本就属 `ai1net-dsh-server/` 域),
|
||
未擅自改该脚本(它是【E】机制层、须独占),本轮按提示改为直接 `handoff-guard.sh --claim-exec --domains ai1net-dsh-server/` 抢锁。
|
||
⇒ 记一笔:**凡动 `交付物/` 下文件,入口预检必失败**,可考虑给白名单补 `交付物`(属机制层改动,未做)。
|
||
|
||
**锁**:已释放(`dsh.py close` 反序释放 ✓)。**未做**:未 commit/push(未明确要求)。
|
||
|
||
---
|
||
|
||
## 去掉工作区下拉后面的「删除」按钮(2026-10-11 11:32–11:38)
|
||
|
||
**用户令**:「去掉工作区后的删除功能」。
|
||
|
||
**改动**(只有 `交付物/项目管理界面/project-board.html` 一份;⛔ `.py` 未动 ⇒ 不用重启 —— 改 `.html` 服务每次请求读盘):
|
||
1. 删按钮元素 `<button id="btndel" …>删除</button>`(头部、下拉框右侧)。
|
||
2. 删它的两处联动:`renderAll()` 里的 `disabled = true`、`renderOne()` 里的 `disabled = false`。
|
||
3. 删 `doDelete()` 整个函数(原先按 `prompt` 选粒度:1=只删目标登记、2=整个工作区送回收站)。
|
||
4. 删 `btndel → doDelete` 的事件绑定。
|
||
5. 删 CSS `button.danger{…}`(全文件只这一个按钮用它)。
|
||
⇒ 五处各留一行注释留痕。
|
||
|
||
**保留未动**:后端 `/api/delete` 端点与 `act_delete()` —— 界面已无入口,留着不影响;删它要动 `.py` 并重启服务,没必要。
|
||
|
||
**验证**:全文件只剩 3 行注释含 `btndel`/`doDelete` 字样、无活引用;线上页面(curl 实测)头部只剩 `[下拉] … +新建目标 [刷新]`,删除按钮已消失。
|
||
|
||
**流程**:抢域锁 `--domains ai1net-dsh-server/` → 改 → `--release-exec` 已释放。
|
||
**并发确认**:改的是接续会话 11:22 刚交付的同一份文件(它做完「加时间+已完成收前 8 +列表页」)⇒ 动手前先确认它的锁已释放、文件 11:22 后无新写入,无冲突。
|
||
|
||
---
|
||
|
||
## 技能库待提交清单盘点(18:53 · 只读)
|
||
|
||
**用户问**:「技能文件有哪些改动需要提交」。相对 HEAD `fd9c902` 共 **8 项**(7 个已跟踪文件 + 1 个未跟踪目录,合计 +59/−294):
|
||
|
||
- `browser-harness/SKILL.md`(今天 10:19):标签页按**页面类型**分(一类页面一个、异类各开一个),依据 10-11 用户原话。
|
||
- `product-planning/SKILL.md`(16:38)+ `…/stage-delivery/assets/video-capture/SKILL.md`(16:38,改写成「交接说明」)+ 删两脚本(`extract_frames.py` −156、`fetch_video.py` −85)
|
||
⇒ **video-capture 今天独立成全局技能**。
|
||
- 未跟踪:`product-planning/references/_留痕/video-capture-已独立-20261011/scripts/`(上面两个脚本的原件留档)。
|
||
- `session-mechanism/scripts/collabctl.py`(04:15,+2):登记 `aigc-idea-impression` 工作区的常驻。
|
||
- `session-mechanism/scripts/goalctl.py`(10:26,+14):**本会话改的** —— 换目标时旧目标收尾「已暂停」。
|
||
|
||
🔴 **发现缺口(已作待拍板项交用户)**:`skills/video-capture/` 已是独立技能,但技能仓白名单(`.gitignore` 只放行 6 个)**不含它**
|
||
⇒ 照现状提交,仓库里的 `product-planning` 只剩一份**指向仓外路径**的交接说明,别处取仓拿不到该能力。
|
||
候选 A 加进白名单一起提交(倾向)/B 照现状提交、留已知缺口/C 压着 product-planning 那三项先不交。
|
||
|
||
---
|
||
|
||
## 🔴🔴 报障:技能包脚本把「这台机器」的路径与工作区清单写死在入库代码里(19:22 用户报,按 §G 交接整改)
|
||
|
||
**用户原话**:「session-mechanism/scripts/ 这里面的代码有问题,这个环境都是针对一台机器的,同步到别的机器把环境都搞坏了」。
|
||
|
||
**根因**:技能包**本来就有**「每台机器一份配置」的机制 —— `install.py --apply` 生成包根 `roots.env`(**不入库**,内含
|
||
`DSH_WS_ROOT` / `DSH_DOCS_ROOT` / `CODEBUDDY_CONFIG_DIR` / `COLLABD_PROD_CONFIG`),各脚本头部 `_sm_load_roots()` 以 setdefault 注入。
|
||
但下面这几处**绕开了它**,把本机路径与本机工作区清单写死在**会入库**的代码里:
|
||
|
||
- `scripts/collabctl.py`:`AIROOT = "E:/ProgramData/AIProject"`(L63)|`WORKSPACES` 四个本机工作区(L67-72)|
|
||
`BOARD_PY` 绝对路径(L75)|`KEEPALIVE_TASKS` 字典(L85-90)。
|
||
- `scripts/keepalive.py`:`PYW` 写死 pythonw 版本路径(L46)|`AIROOT`(L47)|`WS` 字典(L50-53)|`BOARD_PY`(L55)。
|
||
- `scripts/supervise-launch.py`:L28 `CODEBUDDY_CONFIG_DIR = r"E:\ProgramData\.workbuddy"`(setdefault ⇒ 兜底值本机化)。
|
||
- `scripts/board-launch.py`:L20 `DSH_WS_ROOT` 兜底写死本工作区;L29 同上一处。
|
||
|
||
**后果**:同步到别的机器 ⇒ 这些路径全不存在;跑 `collabctl.py on|ensure` 会**建出一批指向空路径的计划任务** —— 这就是"把环境搞坏"。
|
||
|
||
**修法(照既有模式,逐条)**:
|
||
1. `AIROOT` ⇒ 读 `DSH_AIROOT`(新键,落 `roots.env` 与 `.example`);兜底 = `Path(DSH_WS_ROOT).parent`。
|
||
2. `WORKSPACES` ⇒ **自动发现**:扫 `AIROOT` 下装了 `.workbuddy/collab/` 的目录(与项目看板同一套扫法)。
|
||
3. `KEEPALIVE_TASKS` ⇒ 由工作区名推导 `collabd-keepalive-<basename>`,不写死字典。
|
||
4. `BOARD_PY` ⇒ `Path(__file__).resolve().parent / "board.py"`(技能包内相对定位)。
|
||
5. `PYW` ⇒ 优先 `sys.executable`,其次宿主 env,兜底再探测。
|
||
6. 两处 `CODEBUDDY_CONFIG_DIR` 默认值 ⇒ `os.path.expanduser("~/.workbuddy")` 形态。
|
||
7. 改完跑 `selftest.py`(基线 PASS 109 / FAIL 0)+ `install.py --manifest`。
|
||
|
||
**顺带要查的**:用户说"同步到别的机器把环境都搞坏了" ⇒ 若那边**已跑过** `collabctl.py on|ensure`,会留下**指向空路径的计划任务**,需一次清理。
|
||
|
||
**属机制层** ⇒ 开工必须**独占锁**;改完跑自证。
|
||
|
||
**✅ 用户 19:28 拍板(原话)**:「不用挪出 用env文件夹区分就行,重点是 脚本是脚本 配置是配置」
|
||
⇒ 目录划分定为:技能包内建 **`env/`** 放环境专属配置,`scripts/` 只留通用代码;⛔ 不挪到宿主配置目录(我提的候选 A 被否)。
|
||
⇒ 接续任务已按此改写并重排(automation `df3dead8-37ba-4907-95c7-7896bea14383`,改写后:建 `env/`、`roots.env` 与 `.example` 迁入、
|
||
`.gitignore` 挡 `env/` 下非 `.example`、所有 `_sm_load_roots()` 与 `install.py` 的 `ROOTS_ENV` 改指 `env/roots.env`、再做去硬编码那七条)。
|
||
⚠️ 中途曾把它 PAUSED 一次(怕它按旧方案白做),改写后已恢复 ACTIVE,排期 19:32。
|
||
|
||
**✅ 19:29 / 19:30 用户再补两条口径**:
|
||
· 19:29「每个技能 需要环境配置的 都有自己的 env文件夹」⇒ 升格为**全仓包结构规范**,写进技能仓根 `改包纪律.md`;
|
||
并逐个检查其余技能(browser-harness / oil-ui-pro / product-planning / video-capture 各有 scripts;humanizer 两份是纯文档)。
|
||
· 19:30「修改完成后要仔细检查 避免调整后 各技能脚本运行失败」⇒ 验收按**实跑**算,七条:语法编译 / 全套自测 /
|
||
只读入口实跑(collabctl / board / board-launch / supervise-launch / keepalive)/ 4 个工作区常驻心跳与 20099·20100 两个看板活体 /
|
||
改动前后同命令对照 / 把 DSH_WS_ROOT 指到假目录验自适配 / 其他技能脚本同跑;**任一条不过就回滚那一项**。
|
||
任务经两次改写后重排 **19:38**。
|
||
|
||
---
|
||
|
||
## ✅ 19:56 收工:技能包「脚本是脚本、配置是配置」分层**全绿落地**(会话 `[执行]-[技能包env分层]-脚本配置分界`)
|
||
|
||
**做成了什么**
|
||
- **目录**:`session-mechanism/env/` 立起来了 —— `roots.env`(本机真身·不入库)+ `roots.env.example`(入库样例)。`install.py --apply` 现在写 `env/roots.env`。
|
||
- **去硬编码**:`collabctl.py` / `keepalive.py` / `supervise-launch.py` / `board-launch.py` 里写死的本机路径与本机工作区清单**全清**,改为 `DSH_AIROOT`(兜底 `dirname(DSH_WS_ROOT)`)+ 扫 `<AIROOT>/*/.workbuddy/collab/` **自动发现**;任务名按 `collabd-keepalive-<basename>` 推导。
|
||
- **读配置**:全包 **23 个** 脚本/hook 的 loader 统一成 `_cands` 写法 —— 向上 4 层 × (`env/roots.env` 优先 → 包根 `roots.env` 兼容),再兜底「技能库那份」`<CODEBUDDY_CONFIG_DIR>/skills/session-mechanism/env/roots.env`(工作区副本靠这条拿本机配置)。
|
||
- **`.gitignore`**(技能仓根)三层规则:`env/*` + `!env/*.example`(含 `*/` 与 `**/` 变体)⇒ 实测 `git check-ignore -v` 命中正确。
|
||
- **全仓规矩**:技能仓根 `改包纪律.md` 新增「四、包结构:脚本是脚本,配置是配置」;首个补 env 的是 `browser-harness`(`env/bh.env` + `bh.env.example`,`bh_chrome_keepalive.py` 全部默认值改 env 驱动)。
|
||
|
||
**验收读数(七条全过)**
|
||
- `py_compile`:`scripts/**` 34 个 py 全过;`bash -n preflight-lock.sh` 过。
|
||
- `selftest.py`:**PASS 109 / FAIL 0**(报告型 1 条不计)。
|
||
- **逐文件实证 loader**(AST 精确切分函数体、清空 `DSH_WS_ROOT` 后 exec):8/8 命中 `env/roots.env`;`preflight-lock.sh` 抽取片段在同目录执行 ⇒ `DOCS_ROOT`/`WS_ROOT` 均由该文件解出。
|
||
- `install.py --manifest`:**77 份、语法失败 0**(`MANIFEST_SKIP` 加 `env/roots.env` ⇒ 入库清单不随机器变)。
|
||
- 钩子冒烟:4 个改动过的 hook 空输入 rc=0;`supervise-ensure-hook` 真实载荷(cwd=ai1net)rc=0。
|
||
- 自适配:`DSH_AIROOT`/`DSH_WS_ROOT` 皆空 ⇒ 优雅报错 rc=1;指假目录 ⇒ 名单空、不崩、不建错任务。
|
||
- 活体:4 区常驻心跳读出;`:20099` / `:20100` HTTP 200。
|
||
|
||
**遗留(已登记,未动)**
|
||
- 文档库那份 `07-scripts/handoff-guard.sh`(md5 `4437d9da…`)与包内那份(`80d40d9f…`)**不同**,且它仍按位置推导根目录 ⇒ 本次只登记差异,**没改文档库那份**(发源在技能包内)。
|
||
- 3 个指向空路径的垃圾计划任务(`collabd-supervise-agent-product` / `collabd-supervise-selftest` / `dsh-board-20099`)已 `Disabled`(不删)。
|
||
- 技能仓与工作区**均未 commit/push**(用户未提要求)。
|
||
|
||
---
|
||
|
||
## ✅ 21:50 异机验证 + 提交完成(用户:「确认不同机器环境都可独立配置,脚本运行正常就可以提交」+「提交的时候 需要忽略env文件夹」)
|
||
|
||
**异机验证怎么做**:把技能包拷成「新克隆」形态(**删掉 `env/roots.env`,只留 `roots.env.example`**),
|
||
另造一台假机器的两个工作区 `ws-alpha` / `ws-beta`(`<MB>/AIProject/*`),配置目录也换成 `<MB>/conf`。
|
||
|
||
**读数(全部实测)**
|
||
- `install.py --apply --workspace <MB>/AIProject/ws-alpha` ⇒ **自生成该机的 `env/roots.env`**
|
||
(`DSH_AIROOT=<MB>/AIProject`),本机工作区名一个都没漏进去。
|
||
- `collabctl.py status` / `keepalive.py status` 在假机器上**自动发现的是 ws-alpha / ws-beta 两个**,
|
||
任务名现推为 `collabd-keepalive-ws-alpha` / `-ws-beta` ⇒ **写死的本机工作区清单确已消除**。
|
||
- **部署副本桥接**:把 `collabctl.py` 放到假工作区的 `.workbuddy/collab/`(本地无任何 `roots.env`),
|
||
只靠 `CODEBUDDY_CONFIG_DIR` 兜底 ⇒ 正确读到技能库那份 L0,认出本机 4 个区。
|
||
- `board-launch.py`:`DSH_WS_ROOT` 指不存在的目录 ⇒ 拒跑不写文件;留空 ⇒ 优雅报错不崩(⛔ 无写死兜底)。
|
||
- 整套 `selftest.py` 在假机器上:**有宿主库时 PASS 108 / FAIL 1**(唯一 FAIL =
|
||
「本区没有心跳文件 ⇒ 父链这条验不了(不假装通过)」,纯环境;本机常驻在跑时同一套是 **PASS 109 / FAIL 0**)。
|
||
**裸机器(无宿主库)**:能跑,如实报「验不了」,⛔ 不假绿。
|
||
- ⚠️ 沙箱踩坑:`selftest` **后台跑会被沙箱掐在宿主集成那几步**(输出停在副本同步、无「合计」行);
|
||
**前台跑才完整**(会用 escalation 放行)。
|
||
|
||
**提交**
|
||
- 技能仓 `E:/ProgramData/.workbuddy/skills` ⇒ **`d81f75f`**,37 文件、+762/−290。
|
||
只提本轮改动(`.gitignore` / `改包纪律.md` / `session-mechanism` / `browser-harness`);
|
||
**⛔ 没碰** `product-planning` 那笔(video-capture 独立化,属于别的任务)。
|
||
- 发现:20:27 另一个会话的提交 `90cc431` 把我那次 `git mv` 的**纯改名**顺手卷进去了(内容 0 变化)——
|
||
已核,无副作用。
|
||
- **`env/` 忽略实证**(按退出码判):`session-mechanism/env/roots.env` ⛔被忽略 /
|
||
`browser-harness/env/bh.env` ⛔被忽略 / 两个 `*.example` ✅入库 /
|
||
`*.example.bak` ⛔被忽略。头一次用「输出非空=被忽略」判错了(`check-ignore -v` 对
|
||
`!` 反选也会打行),**将来一律看退出码**:0=忽略、1=入库。
|
||
- 另补一条 `.gitignore`:`roots.env`(不带斜杠 ⇒ 按文件名匹配任意层)兜住「旧位置的包根那份」。
|
||
- 全仓 `git ls-files | grep "/env/"` ⇒ **只剩两个 `*.example`**。
|
||
|
||
**遗留**:技能仓 `master` 原先**没有上游**(`git branch -vv` 无 `[origin/master]`)。
|
||
|
||
## ✅ 21:53 用户选 A ⇒ 技能仓已配上游并推送
|
||
|
||
- 推前按技能总仓规矩核对:顶层目录 **6 个技能 + `改包纪律.md`**(白名单符合);
|
||
远端当时停在 `90cc431`,本地 `d81f75f` 领先 1 个提交 ⇒ **快进,无冲突**。
|
||
- `git push -u origin master` ⇒ `90cc431..d81f75f master -> master`,上游已设。
|
||
- 远端复核:`origin/master` = `d81f75f`(与本地同一提交);
|
||
`git ls-tree -r origin/master | grep "/env/"` ⇒ **只有两个 `*.example`**,
|
||
**没有任何 `roots.env` / `bh.env` 真身**(这轮最要紧的一条:配置没跟着上远端)。
|
||
- 工作区仓按惯例补提今日日志。
|
||
|
||
|
||
|
||
|