diff --git a/.workbuddy/memory/2026-10-06.md b/.workbuddy/memory/2026-10-06.md index 573de77..a4bbe9b 100644 --- a/.workbuddy/memory/2026-10-06.md +++ b/.workbuddy/memory/2026-10-06.md @@ -369,3 +369,65 @@ vibe-product 上一条会话(10-06 08:15~08:20)已诊断出两条缺陷并** ⚠️ 这属「**影响面超出本平台/跨工作区状态变更**」⇒ **先报用户,⛔ 不擅自动手**。 ⚠️ 另:vibe-product 常驻主循环跑的是**旧代码**(09-29 启动,配置改动需重启才生效)—— 本次修的是**技能源**,其工作区副本要同步+重启才生效(这一步同样未做)。 + +## 41、项目管理界面改「跨工作区」+ 增删落地(用户:「项目管理管的是本机所有工作区的项目 不是单个工作区的」) + +### 41.1 用户口径(逐字) + +> `项目管理管的是本机所有工作区的项目 不是单个工作区的,可以通过项目管理工具 创建新目标(新工作区),管理目标` + +外加三条 AskUserQuestion 选定:① 项目范围=**只列「装了机制」的工作区**;② 建新目标=**填表建目录+登记目标**; +③ 写权限=**允许增删,改状态交给机制**(承接上一轮 `增删查(状态不需要改 让会话机制自己处理)`)。 + +### 41.2 数据面(🔴 关键设计:直读各区文件,⛔ 不拉各区看板) + +**真因**:并非每个区都起着 `board.py`(本机 3 个装机制的区里只有 1 个在看板跑)⇒ 拉看板会**静默漏掉没起看板的区**。 +✅ 改直读:`<区>/tmp/supervise-inbox/goal.json`(项目)+ `tasks.json`(卡片)+ `collabd-state.json`(队列) ++ `<区>/.workbuddy/collab/collabd.config.json`(判「装没装机制」)。 + +**「装了机制」判据**:① 有 `collabd.config.json` 或 ② 有 `goal.json`(两条任一)。 +🔴 跳过的**也要带出来**(`skipped` 列表)—— 同族 P0「作用域不许静默排除」,⛔ 不静默丢。 + +### 41.3 新增能力 + +| 能力 | 实现 | 实测 | +|---|---|---| +| **查** | `GET /api/projects` | 3 个项目(本机协作 / vibe-product / agent-product 空壳)+ 12 个未装机制目录 | +| **增** | `POST /api/create` → `init_workspace.py` | `ok=True rc=0`,骨架+目标登记齐全 | +| **删(轻)** | `POST /api/delete {mode:"goal"}` | `goal.json` → `goal.json.archived-<时间戳>`(可逆) | +| **删(重)** | `POST /api/delete {mode:"ws"}` | **送系统回收站**(可逆) | + +### 41.4 🔴🔴 本机回收站:`gio` 不存在,改走 `SHFileOperationW` + +**症状**:`mode="ws"` 原写 `gio trash` ⇒ `gio: command not found`(PortableGit 里 `gio`/`trash-put`/`trash` **一个都没有**); +改用 PowerShell `[Microsoft.VisualBasic.FileIO.FileSystem]` ⇒ **被安全策略拦**("Add-Type compiles and loads .NET code at runtime")。 + +**✅ 正解**:纯 `ctypes` 调 Windows Shell API `SHFileOperationW`(不编译代码、不碰 .NET、不弹 UAC)。 +**三个坑**(都踩过): + +1. 🔴 `pFrom` **必须手搓双 `\0` 结尾缓冲** —— `LPCWSTR` 会在**第一个 `\0` 截断** ⇒ 字段类型必须写 `c_void_p`, + 用 `ctypes.create_unicode_buffer(abspath, len(abspath)+2)` 再 `cast` 塞进去。⛔ 不能直接赋 `str`。 +2. 🔴🔴 **判据不是 `rc == 0`**:送回收站**成功**(目录消失、`$I` 元数据可解出原路径),返回值却**恒为 `rc=2`** + (`ERROR_FILE_NOT_FOUND`,Shell 内部探测残留的 `GetLastError`)⇒ 拿 `rc` 当判据会**假报错** + (用户看到"失败"但东西已进回收站)。✅ 真判据只有两条:**① 原路径不存在了 ② `fAnyOperationsAborted` 为假**。 +3. ⚠️ 回收站 `$I` 元数据:`v2` 格式、路径是 **UTF-16LE**、起点 **offset 24**(⛔ 不是 26;开头 4 字节是长度前缀)。 + 验证可恢复性时按此解析。 + +**实测取证**:`_pmtest-{verify,trash,wsdel,wsdel2,http}` 全部送进 `E:/$RECYCLE.BIN/S-1-5-21-…-500/`, +共 **29+ 条 `$I` 元数据**,逐条解出的原路径与送入路径一致 ⇒ **可恢复**。 + +### 41.5 另一个已修缺陷:子进程中文乱码 + +`init_workspace.py` 输出 **UTF-8**(开头 `reconfigure("utf-8")`),而 `subprocess.run` 不给 `encoding` +时按**本机默认编码(中文 Windows=GBK)**解码 ⇒ 中文全变乱码。✅ 修:`encoding="utf-8"` + `PYTHONIOENCODING=utf-8`。 + +### 41.6 起服务:只许触发计划任务 + +`(python project-board.py --serve 20100 &)` **活不过工具调用边界**(被 SIGTERM)。 +✅ `Start-ScheduledTask -TaskName 'dsh-project-board-keepalive'`(动作走 `pythonw.exe` + `project-board-launch.py`, +⛔ 不直起业务脚本 —— 同族 P0-73/74)。重启后 PID `64312` → `10408`,`/healthz` HTTP 200。 + +### 41.7 挂账 + +- 🔴 **vibe-product 是否收工** —— 仍待用户拍板(见 §40.8,未动)。 +- 🔴 技能仓历史分叉未决(§36,仍待拍板)。 diff --git a/交付物/项目管理界面/project-board.html b/交付物/项目管理界面/project-board.html index 25283d0..47c0da7 100644 --- a/交付物/项目管理界面/project-board.html +++ b/交付物/项目管理界面/project-board.html @@ -65,6 +65,34 @@ color:#f4c67a;font-size:12.5px} .errline{margin:0 0 12px;padding:10px 12px;border-radius:8px; background:rgba(229,83,75,.1);border:1px solid rgba(229,83,75,.4);color:#f2a09a} + .okline{margin:0 0 12px;padding:10px 12px;border-radius:8px; + background:rgba(63,185,80,.1);border:1px solid rgba(63,185,80,.4);color:#8fe39a; + font-size:12.5px;white-space:pre-wrap;word-break:break-word} + pre.out{margin:8px 0 0;padding:10px;border-radius:8px;background:#12141a; + border:1px solid var(--line);color:var(--dim);font-size:11.5px; + max-height:260px;overflow:auto;white-space:pre-wrap} + + button.primary{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600} + button.danger{background:transparent;border-color:rgba(229,83,75,.5);color:#f2a09a} + button.danger:hover{background:rgba(229,83,75,.12)} + button[disabled]{opacity:.5;cursor:not-allowed} + + /* ── 新建对话框 ── */ + .modal{position:fixed;z-index:40;left:50%;top:50%;transform:translate(-50%,-50%) scale(.98); + width:min(560px,92vw);background:var(--panel);border:1px solid var(--line); + border-radius:12px;box-shadow:0 18px 50px rgba(0,0,0,.5); + opacity:0;pointer-events:none;transition:opacity .14s ease,transform .14s ease} + .modal.on{opacity:1;pointer-events:auto;transform:translate(-50%,-50%) scale(1)} + .hint{color:var(--dim);font-size:12.5px;margin:0 0 14px} + .hint b{color:var(--fg)} + .fld{display:flex;flex-direction:column;gap:5px;margin-bottom:11px} + .fld>span{color:var(--dim);font-size:12px} + .fld input,.fld select{background:var(--panel2);color:var(--fg);border:1px solid var(--line); + border-radius:8px;padding:8px 10px;font:inherit;width:100%} + .fld input:focus,.fld select:focus{outline:2px solid var(--accent);outline-offset:1px} + .fnote{margin:2px 0 12px;font-size:12px;color:var(--dim2);min-height:1.2em} + .fnote.bad{color:#f2a09a} + .facts{display:flex;align-items:center;gap:10px} /* ── 抽屉 ── */ .mask{position:fixed;inset:0;background:rgba(0,0,0,.5);opacity:0;pointer-events:none; @@ -99,8 +127,10 @@
项目管理—
+
加载中… +
@@ -120,6 +150,32 @@
+ +
+ +