建立 Claude Office 虛擬辦公室(模擬 + 實況雙模式)

摘要:
參考 WW-AI-Lab/openclaw-office(MIT)的 office-2d 邏輯,重新實作 Claude 風格的
multi-agent 虛擬辦公室:四分區平面圖、走廊尋路、chibi 小人、狀態表情氣泡、
subagent 熱桌、會議聚集,以及可視化真實 Claude Code 活動的實況模式。

根本原因:
需要一個能一眼看出各專案 Claude Code 工作狀態(是否派發任務、調用工具、
派生 subagent)的監控介面,現有工具沒有對應的視覺化。

影響:
新專案,不影響既有系統。實況模式的監看伺服器僅綁 localhost:5179,
會讀取本機 ~/.claude/projects/ 的 session transcripts。

修法:
- Vite 6 + React 19 + Zustand,SVG 平面圖 + CSS 動畫,實測 60fps
- src/sim/director.ts:劇本模擬引擎(FSM + 會議排程)
- server/watch.mjs:零依賴 Node watcher,tail JSONL 轉譯為 SSE 事件
- src/gateway/live.ts:事件對映 store action,支援模式即時切換

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 12:31:18 +08:00
co-authored by Claude Fable 5
commit f935a2ef2d
29 changed files with 5802 additions and 0 deletions
+44
View File
@@ -0,0 +1,44 @@
import { Director } from "./director";
import { useOfficeStore } from "@/store/office-store";
import { liveConnect, liveDisconnect } from "@/gateway/live";
let director = new Director();
let running = false;
export function getDirector() {
return director;
}
/** Switch between the scripted simulation and the live transcript feed. */
export function setMode(mode: "sim" | "live") {
const S = useOfficeStore.getState();
if (S.mode === mode) return;
S.clearWorld();
S.setMode(mode);
if (mode === "sim") {
liveDisconnect();
director = new Director();
} else {
liveConnect();
}
}
/** Single rAF loop: advances the store clock/movements, then the director's FSMs. */
export function startRuntime() {
if (running) return;
running = true;
let last = performance.now();
const frame = (now: number) => {
const raw = Math.min((now - last) / 1000, 0.1);
last = now;
const S = useOfficeStore.getState();
if (!S.paused) {
const dt = raw * S.speed;
S.tick(dt);
if (S.mode === "sim") director.update(dt);
}
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
}