| name | code-quest-review |
| description | Code Quest project-specific code review checks covering import order, zod schema placement, cross-package event-name alignment, server handler middleware, channel / emitter semantics, client handler organization, React Compiler compatibility, icon facade convention, and FakeSummoner test patterns. Pairs with generic `code-review` skill. Use when reviewing Code Quest code, discussing refactor, checking a PR for protocol/handler/zod alignment, or verifying that recent changes match project conventions.
|
Code Quest 專案特定 Code Review
除通用 /code-review skill 的審查維度外,本專案額外檢查以下項目。
Import
- import 放在檔案最頂部,不要 inline import(函式中間寫 import)
- Node.js built-in import(
node:path, node:fs)放最上方
isolatedDeclarations
summoner package 開啟了 isolatedDeclarations: true,影響:
- exported 變數必須有顯式型別標注 — 不可依賴推導,這不是冗餘
- schema 檔(
schemas.ts、launch-options.ts)的縮寫型別別名(Opt、Str、Num、Bool、Unk、Loose)是為了簡化這些必要標注,屬合理設計,不應移除
- 審查時看到 schema export 帶顯式型別,不要標為「冗餘型別標注」
Zod
.passthrough() / .loose() → 改 z.looseObject()(Zod v4 deprecated)
- shared schema 只有一個 package 使用 → 搬到該 package
payload as { ... } inline type assertion → 改用 zod schema parse:
- 先查 shared schemas 有沒有現有 schema 可用
- 沒有才新建,放 shared 讓前後端共用
- 不要 inline
z.looseObject({...}).parse(payload) — 那只是換一種 inline,應該抽成 named schema
跨 Package 對齊(shared / summoner / server / client)
- server
emitter.on('event', ...) 的 event name 跟 shared socket-events.ts 定義是否一致
- server
ch.sendRequest('event', ...) 的 event name 跟 adapter REQUEST_MAPPINGS 是否一致
- adapter
transformControlRequest 產出的 event name 跟 server handler 訂閱的是否一致
- client handler on map 的 event name 跟 server emit 給 client 的是否對齊
- shared
ClientToServerEvents / ServerToClientEvents 定義跟實際 emit/on 是否同步
summoner(CLI adapter)
REQUEST_MAPPINGS 是否涵蓋所有 ch.sendRequest 呼叫的 event name
- adapter transform 每個 case 是否都有 named function(不用 inline arrow)
isRecord() 等 util 是否集中在 utils.ts,不重複定義
ProcessRunner 終止方法只有 kill()(底層呼叫 handle 的 abort())— 不要再加 abort() wrapper
console.debug / console.log → 改用 logger(pino),注意 pino API 第一個參數是 object:logger.debug({ err }, 'message')
server handler
- middleware 是否正確:
- 需要 channel 且有 callback →
withError(withChannel(handler))
- 需要 channel 無 callback →
withChannel(handler)
- 需要 socket →
withSocket(handler)
- 不需要 channel → 直接註冊
- handler 使用
ch.sendRequest('event', payload) 不直接用 protocol subtype
- handler 使用 named function(不用 arrow)
- handler 內
respondToRequest 只在 auto-respond 或 CLI-initiated event 使用
server core
Channel 的 mutable field 必須 private + getter/setter
ChannelEmitter 的 emit / emitToOthers / dispatch 語義區分:
emit → broadcast 給 channel sockets(server → client)
dispatch → 呼叫 server handler
dispatchRunnerEvent → broadcast + dispatch(runner event 專用)
client handler
- handler 檔案放在
contexts/channel/handlers/
- 命名對齊 server:
file.ts、message.ts、permission.ts...(無 Handler suffix)
- 只有一個 consumer 的 helper → inline 到 consumer,不獨立檔案
- handler map export 用
satisfies Record<string, ...> 確保型別
- effects 和 state handlers 分開 export:
xxxHandlerOn + xxxHandlerEffects
Icon 慣例
- 優先用
ui/Icons facade(re-export heroicons + ActionButton + SlashCommandIcon)
- 新 icon 需求 → 先找 heroicons
/24/outline;沒對應才自訂
- 自訂 SVG 情境(合法):
- brand mark(
✦)
- extension 視覺 parity(
PermissionModeIcons)
- dynamic chart(
SparkLegend EffortDots)
- SVG 尺寸慣例:svgBase 用
width: '100%'; height: '100%',由 wrapper w-X h-X 控渲染尺寸(跟 data-font axis 等比縮放)
React Compiler 相容性
已啟用 babel-plugin-react-compiler。檢查:
- render 時不讀 ref.current(compiler 可能重排序)— ref 只在 useEffect / event handler 裡讀
- component 必須是純函式(相同 props → 相同 output)
- 不依賴 render 順序的 side effect
- 手動 useMemo/useCallback 不必要時可移除(compiler 自動 memoize)
UI / 樣式(design token first)
- JSX 看到 arbitrary utility(
text-[13px] / bg-[#...] / p-[7px] / shadow-[...])先查有沒有對應 @theme token
- 差 1–2px / 1–2 階 → 就近取內建 utility(
text-xs / p-2)
- 超出既有範圍 → 先擴
@theme,不要直接 arbitrary
- 合法 arbitrary:
calc(...)、引用 CSS variable、刻意 off-grid 且有理由
- 顏色不寫 hex:查
apps/web/src/App.css 的 --color-* 語意 token(accent / surface / text-muted / success / danger…)
- 細節流程參考
tailwind-v4 skill 的「Design flow: token-first」
測試
測試寫法慣例
- Summoner 相關測試應使用
FakeSummonerClient / FakeSummonerServer 建立 test double,詳見 fake-summoner-client / fake-summoner-server skill
- 使用 FakeSummoner + real JSON segments(
@code-quest/summoner/test 的 s.*() builder)
- 驗證 action 發 socket event 用完整 pipeline +
claude.received(...),不 spy emit
- client 測試用
renderWithChannel / renderWithWorkspace + testing-library
- expect 不變原則:重構不改 expect