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 跟 sharedsocket-events.ts定義是否一致 - server
ch.sendRequest('event', ...)的 event name 跟 adapterREQUEST_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()wrapperconsole.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 → 直接註冊
- 需要 channel 且有 callback →
- 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/setterChannelEmitter的emit/emitToOthers/dispatch語義區分:emit→ broadcast 給 channel sockets(server → client)dispatch→ 呼叫 server handlerdispatchRunnerEvent→ 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/Iconsfacade(re-export heroicons +ActionButton+SlashCommandIcon) - 新 icon 需求 → 先找 heroicons
/24/outline;沒對應才自訂 - 自訂 SVG 情境(合法):
- brand mark(
✦) - extension 視覺 parity(
PermissionModeIcons) - dynamic chart(
SparkLegendEffortDots)
- brand mark(
- SVG 尺寸慣例:svgBase 用
width: '100%'; height: '100%',由 wrapperw-X h-X控渲染尺寸(跟data-fontaxis 等比縮放)
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-[...])先查有沒有對應@themetoken- 差 1–2px / 1–2 階 → 就近取內建 utility(
text-xs/p-2) - 超出既有範圍 → 先擴
@theme,不要直接 arbitrary - 合法 arbitrary:
calc(...)、引用 CSS variable、刻意 off-grid 且有理由
- 差 1–2px / 1–2 階 → 就近取內建 utility(
- 顏色不寫 hex:查
apps/web/src/App.css的--color-*語意 token(accent/surface/text-muted/success/danger…) - 細節流程參考
tailwind-v4skill 的「Design flow: token-first」
測試
測試寫法慣例
- Summoner 相關測試應使用
FakeSummonerClient/FakeSummonerServer建立 test double,詳見fake-summoner-client/fake-summoner-serverskill - 使用 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