From d662a38944e01c78b6125c070b8a0082f60d5aac Mon Sep 17 00:00:00 2001 From: maogeigei Date: Mon, 19 Oct 2026 22:40:02 +0800 Subject: [PATCH] =?UTF-8?q?feat(board):=20=E5=8D=A1=E7=89=87=E6=A0=87?= =?UTF-8?q?=E6=9C=BA=E5=88=B6=E6=A0=87=E7=AD=BE=20loop=EF=BC=8F=E5=9B=BE?= =?UTF-8?q?=EF=BC=88=E7=94=A8=E6=88=B7=EF=BC=9A=E6=80=8E=E5=8C=BA=E5=88=86?= =?UTF-8?q?=E9=82=A3=E4=B8=AA=E9=A1=B9=E7=9B=AE=E6=98=AF=20loop=20?= =?UTF-8?q?=E6=9C=BA=E5=88=B6=20=E9=82=A3=E4=B8=AA=E6=98=AF=E5=9B=BE?= =?UTF-8?q?=E6=9C=BA=E5=88=B6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../boards/项目看板/project-board.html | 22 +++++++++++++++++-- .../boards/项目看板/project-board.py | 16 ++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/session-mechanism/boards/项目看板/project-board.html b/session-mechanism/boards/项目看板/project-board.html index 745e396..0be33e0 100644 --- a/session-mechanism/boards/项目看板/project-board.html +++ b/session-mechanism/boards/项目看板/project-board.html @@ -282,6 +282,9 @@ .gchip.gst-gating { border-color: #b48bff; background: rgba(180,139,255,.16); } .gchip.gst-skipped, .gchip.gst-cancelled { opacity: .45; } .gempty { opacity: .55; font-size: 12px; padding: 6px 0; } + /* 机制标签(卡片上):loop=现有项目机制,图=图模式有图 */ + .badge.mech-loop { background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.30); } + .badge.mech-graph { background: rgba(180,139,255,.18); border: 1px solid #b48bff; color: #e8dcff; }
@@ -497,7 +500,18 @@ function _cardHtml(t){ ? '
'+esc(t._ws)+''+ (t._self ? '本工作区' : '')+'
' : ''; - var badges = ''+esc(t.life||"")+''; + var badges = ''; + // 🔴 机制标签先出(用户 2026-10-19:「怎区分那个项目是 loop 机制 那个是 图机制」): + // loop = 现有项目机制那套(目标+排队+检查会话推进);图 = `.workbuddy/graph/` 里有图。 + // 两套并存就两个都挂 —— 图模式本来就是并列机制,⛔ 不逼它二选一。 + (t._mech || []).forEach(function(m){ + var cls = (m === '图') ? 'mech-graph' : 'mech-loop'; + var tip = (m === '图') + ? ('图模式:.workbuddy/graph 下有 ' + (t._gcount || 0) + ' 张图') + : 'loop 机制:目标登记 + 协作队列 + 检查会话推进'; + badges += '' + esc(m) + ''; + }); + badges += ''+esc(t.life||"")+''; if(t.current) badges += '当前'; // 🔴 2026-10-18:目标「状态未收口」明说(后端判据:非已完成 且 无判据/判据全未过) if(t.warn) badges += ''+esc(t.warn)+''; @@ -537,6 +551,9 @@ function _collectCards(){ x._goal = p.name; // 目标短名(⛔ 不上卡片标签,仅供详情/排查) x._self = !!p.self; // 🔴 本工作区 ⇒ 卡片换色突出 x._life = p.life || ""; + // 🔴 机制标签(loop/图):跟着**工作区**走,不跟目标走 —— 同一区里所有卡片一样 + x._mech = (p.mech && p.mech.labels) || []; + x._gcount = (p.mech && p.mech.graph_count) || 0; out.push(x); }); }); @@ -842,7 +859,8 @@ function paintGraphs(){ return; } var h = ['
图模式' - + rows.length + ' 张图 · 胶囊上的粗体是节点类型,颜色是状态
']; + + rows.length + ' 张图 · 胶囊上的粗体是节点类型,颜色是状态' + + ' · 卡片上的 loop = 目标队列推进、图 = 本区有图']; rows.forEach(function(r){ var g = r.g, p = r.p; h.push('
' + esc(g.title) diff --git a/session-mechanism/boards/项目看板/project-board.py b/session-mechanism/boards/项目看板/project-board.py index c8d0ca9..5fb3069 100644 --- a/session-mechanism/boards/项目看板/project-board.py +++ b/session-mechanism/boards/项目看板/project-board.py @@ -432,6 +432,20 @@ def graph_view(ws: Path) -> dict: return {"graphs": graphs, "count": len(graphs), "dir": str(base).replace("\\", "/")} +def mech_view(ws: Path, goal: dict, tasks: dict, st: dict) -> dict: + """这个工作区在跑哪套机制(用户 2026-10-19:「怎区分那个项目是 loop 机制 那个是 图机制」)。 + + · `loop` = 现有项目机制那套(有目标登记/台账/协作状态 ⇒ 目标是靠「队列+检查会话」推进的) + · `图` = 图模式那套(`.workbuddy/graph//` 下有图) + 两套并存 ⇒ 两个标签都给(图模式本来就是并列的,⛔ 不强行二选一)。 + """ + gv = graph_view(ws) + loop = bool(str(goal.get("title") or "").strip() or tasks or st) + labels = (["loop"] if loop else []) + (["图"] if gv["count"] else []) + return {"loop": loop, "graph": gv["count"], "labels": labels, + "graph_count": gv["count"]} + + def build_project(ws: Path) -> dict: """把**一个工作区**读成「项目」(纯读,⛔ 不写任何东西)。""" inbox = ws / "tmp" / "supervise-inbox" @@ -624,6 +638,8 @@ def build_project(ws: Path) -> dict: "life_unknown": life_unknown, # 🔴 图模式快照(只读):`/.workbuddy/graph/*/graph.json` ⇒ 前端「图模式」块 "graph": graph_view(ws), + # 🔴 机制标签:loop(目标+队列)/图(图模式) + "mech": mech_view(ws, goal, tasks, st), "acc": {"n": len(eff), "pass": acc_pass, "items": acc_items}, "region": str(_region_dir(ws, goal)).replace("\\", "/"), "port": cfg.get("singleton_port"),