From a94c334767176f412cc800b71219b1d92cb3f258 Mon Sep 17 00:00:00 2001 From: BeastAyyG Date: Sat, 19 Sep 2026 16:05:39 +0530 Subject: [PATCH] docs(windows): add Windows hook wiring guide Document why TeamAI hooks silently fail on Windows (bare bash -> WSL Node 18 crash; hasShell() /bin/sh check skips codebuddy/workbuddy) and provide a durable user-side fix (Git Bash absolute path + WSL wrapper). Include a suggested upstream fix for maintainers. Bilingual (en + zh-CN) to match repo docs convention. --- docs/windows-hooks.md | 276 ++++++++++++++++++++++++++++++++++++ docs/windows-hooks.zh-CN.md | 263 ++++++++++++++++++++++++++++++++++ 2 files changed, 539 insertions(+) create mode 100644 docs/windows-hooks.md create mode 100644 docs/windows-hooks.zh-CN.md diff --git a/docs/windows-hooks.md b/docs/windows-hooks.md new file mode 100644 index 00000000..073b9e0b --- /dev/null +++ b/docs/windows-hooks.md @@ -0,0 +1,276 @@ +# TeamAI on Windows — getting hooks to actually fire + +> A practical guide for running the TeamAI CLI (`teamai`) hook wiring on +> **Windows** for every enabled agent (Claude Code, Codex, ZCode, CodeBuddy, +> Qoder, WorkBuddy, Cline, Cursor, OpenCode), plus the upstream bug that makes +> this necessary and a suggested fix for maintainers. + +## TL;DR + +On Windows the hooks TeamAI injects use a bare `bash` launcher that silently +crashes (the WSL `bash` ships Node 18, which can't parse the TeamAI bundle), so +the hooks are effectively dead — `|| true` hides the failure. In addition, +`codebuddy` / `workbuddy` hooks are **never written at all** because TeamAI's +shell detection (`fs.existsSync('/bin/sh')`) is always false on Windows. + +The durable user-side fix combines two mechanisms so hooks fire no matter what +`teamai` writes: + +1. **Git Bash absolute path** in every agent settings file (works today). +2. **A WSL wrapper** that delegates to the native Windows `teamai` via + `cmd.exe` (survives a later `teamai pull` that reverts the hooks to bare + `bash`). + +After applying both, `teamai doctor` reports the six installed tools as healthy +and every `hook-dispatch` call returns `exit=0` through both mechanisms. + +--- + +## How TeamAI hooks work (quick recap) + +`teamai hooks inject` writes a command like this into each agent's settings +file: + +```json +"command": "bash -lc \"teamai hook-dispatch session-start --tool claude 2>/dev/null\" || true" +``` + +There are six hooks per tool: `SessionStart`, `Stop`, `PostToolUse` (three +matchers: `*`, `Skill`, `TodoWrite`), and `UserPromptSubmit`. They let the team +repo record session stats and apply shared rules/skills across agents. + +--- + +## The problem on Windows + +### Failure mode 1 — bare `bash` → WSL Node 18 crash + +On Windows a bare `bash` on `PATH` resolves to the **WSL launcher** +(`C:\Windows\System32\bash.exe`). WSL's bundled Node is **v18**, but the TeamAI +bundle needs a newer Node, so every hook invocation crashes silently. Because +the command ends in `|| true`, the crash is swallowed and nothing is logged — +hooks never fire, yet `teamai doctor` still reports them as "present". + +### Failure mode 2 — `hasShell()` skips CodeBuddy / WorkBuddy + +`src/builtin-hooks.ts` gates shell-dependent tools on `hasShell()`: + +```ts +export function hasShell(): boolean { + if (_hasShellCache === undefined) { + try { + _hasShellCache = fs.existsSync('/bin/sh'); + } catch { + _hasShellCache = false; + } + } + return _hasShellCache; +} +``` + +`/bin/sh` does not exist on Windows, so `hasShell()` is `false` and +`skipToolsWithoutShell()` adds `codebuddy` / `workbuddy` +(`SHELL_DEPENDENT_TOOLS`) to the skip set. Those two agents get **no hooks at +all** on Windows, even when everything else works. + +> Note: `workbuddy` has a partial escape hatch — `hasShellFor()` returns `true` +> if `bundledShellFor(tool)` finds WorkBuddy's bundled PortableGit `sh.exe`. But +> that only helps if that exact binary is present, and `codebuddy` has no +> bundled shell, so it is skipped unconditionally on Windows. + +--- + +## Root causes + +1. **Bare `bash` → WSL Node 18.** Windows `PATH` resolves `bash` to the WSL + launcher before Git Bash; WSL Node 18 can't parse the TeamAI bundle. +2. **`hasShell()` Windows bug.** `fs.existsSync('/bin/sh')` is never true on + Windows, so hook injection for `codebuddy` / `workbuddy` is skipped. +3. **WSL path translation.** A WSL-side wrapper that `exec`s the Windows Node + with a `/mnt/c/...` path gets mangled into `C:\mnt\c\...`, causing + `MODULE_NOT_FOUND`. + +--- + +## The fix (user-side, durable) + +### Mechanism A — Git Bash absolute path in every agent settings file + +Replace the bare `bash` in each hook command with Git Bash's absolute Windows +path (adjust if Git is installed elsewhere): + +```json +"command": "\"C:\\Program Files\\Git\\bin\\bash.exe\" -lc \"teamai hook-dispatch session-start --tool 2>/dev/null\" || true" +``` + +Apply this to every agent that has hooks: + +- `~/.claude/settings.json` — 6 hooks +- `~/.codex/hooks.json` — 6 hooks +- `~/.zcode/cli/config.json` — `command` field → Git Bash path; 6 hooks +- `~/.codebuddy/settings.json` — create if missing; 6 hooks +- `~/.qoder/settings.json` — create if missing; 6 hooks +- WorkBuddy / Cline / Cursor / OpenCode settings as applicable + +Use a JSON-aware edit (don't hand-edit with `sed` — the double quotes must stay +escaped). Keep a `*.teamai-bak` copy of each original file so you can roll back. + +### Mechanism B — WSL wrapper (durability against `teamai pull`) + +`teamai pull` / `hooks inject` rewrites the agent settings back to bare `bash`. +Mechanism A gets overwritten, but a WSL wrapper keeps bare `bash` working. +Create a wrapper at your WSL home (e.g. `/home//.teamai-wsl/bin/teamai`): + +```sh +#!/bin/sh +# delegate to the native Windows teamai (correct Node + paths) via cmd.exe +exec cmd.exe /c teamai "$@" +``` + +Prepend it to `PATH` from `~/.profile` / `~/.bashrc` under a marker: + +```sh +# [teamai-wsl-fix] +export PATH="$HOME/.teamai-wsl/bin:$PATH" +``` + +Now a bare `bash` hook finds `teamai` → `cmd.exe` → native Windows TeamAI. The +`cmd.exe` delegation sidesteps the WSL `/mnt/c` path-translation bug entirely. +**This requires WSL to stay installed.** + +### Completeness for all tools + +- Add `qoder` and `codebuddy` to `enabledAgents` in `~/.teamai/config.yaml`. +- Copy the team's skills and rules from the team repo into `~/.qoder` and + `~/.codebuddy` so those agents are fully equipped, not just hooked. + +--- + +## Verification (all green) + +```sh +teamai doctor +``` + +Expected: hooks present for **claude, codex, qoder, zcode, codebuddy, +workbuddy**. + +Per-tool dispatch check, both ways: + +```sh +# Mechanism A (Git Bash absolute path) +"C:\Program Files\Git\bin\bash.exe" -lc "teamai hook-dispatch session-start --tool claude 2>/dev/null"; echo $? + +# Mechanism B (bare bash via WSL wrapper) +wsl bash -lc "teamai hook-dispatch session-start --tool claude 2>/dev/null"; echo $? +``` + +Every tool should print `0` through both mechanisms. + +```text +doctor: ✔ claude ✔ codex ✔ qoder ✔ zcode ✔ codebuddy ✔ workbuddy +dispatch (Git-Bash path): claude=0 codex=0 zcode=0 codebuddy=0 qoder=0 +dispatch (bare bash/WSL): claude=0 codex=0 zcode=0 codebuddy=0 qoder=0 workbuddy=0 +``` + +--- + +## Limitations / what it can't do + +- **Durability depends on the WSL wrapper.** `teamai pull` reverts agent + settings to bare `bash`; Mechanism A is overwritten, Mechanism B keeps it + working *only while WSL is installed*. If WSL is removed, bare-`bash` hooks + break again. +- **Requires WSL for Mechanism B.** On a machine without WSL, only Mechanism A + (the Git-Bash absolute path currently in the files) works. +- **Does not patch TeamAI itself.** The upstream `hasShell()` bug and the + bare-`bash` default are not fixed inside `teamai-cli`. After + `npm update teamai-cli` re-apply this fix (or rely on the WSL wrapper). +- **macOS / Linux need no fix.** There, bare `bash` already resolves to the + system Node and works natively. +- **`teamai doctor` `gh` check can be a false negative.** It may spawn `gh` + without `APPDATA`, so it can't see your login even though `gh auth status` + shows you as logged in. Ignore it if your other checks pass. +- **Backup files remain.** `*.teamai-bak` copies of the edited agent settings + are kept as rollback safety. + +--- + +## Suggested upstream fix (for maintainers) + +Two small changes would make Windows work out of the box: + +### 1. Make `hasShell()` Windows-aware + +On Windows, `/bin/sh` is absent but a usable POSIX shell is provided by Git for +Windows (`sh.exe` / `bash.exe`) or WSL. `hasShell()` should detect that instead +of always returning `false`: + +```ts +export function hasShell(): boolean { + if (_hasShellCache === undefined) { + try { + if (process.platform === 'win32') { + // Git for Windows ships sh.exe/bash.exe; WSL also provides bash. + // Hooks are launched via `bash -lc ...`, so any of these counts. + const candidates = [ + 'C:\\Program Files\\Git\\bin\\bash.exe', + 'C:\\Program Files\\Git\\usr\\bin\\sh.exe', + 'C:\\Windows\\System32\\bash.exe', + ]; + _hasShellCache = candidates.some((p) => fs.existsSync(p)) || + whichBash() !== null; + } else { + _hasShellCache = fs.existsSync('/bin/sh'); + } + } catch { + _hasShellCache = false; + } + } + return _hasShellCache; +} +``` + +This alone would let `codebuddy` / `workbuddy` hooks be injected on Windows. + +### 2. Default the dispatch command to an absolute Git Bash path on Windows + +`getDispatchCommand()` hard-codes `bash -lc "..."`. On Windows that resolves to +WSL's Node 18 and crashes. Prefer the Git Bash absolute path (or the bundled +PortableGit `sh.exe`) when `process.platform === 'win32'`. + +Both changes are backward compatible: macOS/Linux keep `/bin/sh`, and Windows +users stop needing the manual workaround above. + +--- + +## Troubleshooting + +```sh +teamai doctor + +# per tool, both ways: +"C:\Program Files\Git\bin\bash.exe" -lc "teamai hook-dispatch session-start --tool claude 2>/dev/null"; echo $? +wsl bash -lc "teamai hook-dispatch session-start --tool claude 2>/dev/null"; echo $? + +# if a tool's hooks stop firing: +# 1. confirm the wrapper exists: ls ~/.teamai-wsl/bin/teamai +# 2. confirm PATH export in ~/.profile (marker # [teamai-wsl-fix]) +# 3. otherwise re-apply Mechanism A (Git-Bash absolute path in the agent settings) +``` + +--- + +## Files changed (typical user-side layout) + +| File | Change | +|------|--------| +| `~/.claude/settings.json` | hook commands → Git Bash absolute path (backup: `*.teamai-bak`) | +| `~/.codex/hooks.json` | hook commands → Git Bash absolute path (backup: `*.teamai-bak`) | +| `~/.zcode/cli/config.json` | `command` field → Git Bash path (backup: `*.teamai-bak`) | +| `~/.codebuddy/settings.json` | created with 6 hooks (if missing) | +| `~/.qoder/settings.json` | created with 6 hooks (if missing) | +| `~/.teamai/config.yaml` | `enabledAgents` += `qoder`, `codebuddy` | +| `~/.qoder/{skills,rules}`, `~/.codebuddy/{skills,rules}` | team resources copied | +| `~/.teamai-wsl/bin/teamai` (Win) + `/.teamai-wsl/bin/teamai` (WSL) | durability wrapper | +| `~/.profile`, `~/.bashrc` | PATH export (marker `# [teamai-wsl-fix]`) | diff --git a/docs/windows-hooks.zh-CN.md b/docs/windows-hooks.zh-CN.md new file mode 100644 index 00000000..b6f181e1 --- /dev/null +++ b/docs/windows-hooks.zh-CN.md @@ -0,0 +1,263 @@ +# TeamAI 在 Windows 上的使用 — 让钩子真正生效 + +> 一份在 **Windows** 上为每个已启用代理(Claude Code、Codex、ZCode、CodeBuddy、 +> Qoder、WorkBuddy、Cline、Cursor、OpenCode)正确接入 TeamAI CLI(`teamai`) +> 钩子的实践指南,并说明导致此问题的上游 bug 以及给维护者的修复建议。 + +## 摘要(TL;DR) + +在 Windows 上,TeamAI 注入的钩子使用裸 `bash` 启动器,会**静默崩溃**(WSL 的 +`bash` 自带 Node 18,无法解析 TeamAI 打包产物),因此钩子实际上处于失效状态—— +`|| true` 把错误吞掉了。此外,`codebuddy` / `workbuddy` 的钩子**根本不会被写入**, +因为 TeamAI 的 shell 检测(`fs.existsSync('/bin/sh')`)在 Windows 上永远为 +假。 + +持久化的用户侧修复结合两种机制,无论 `teamai` 写入什么都能让钩子触发: + +1. **在每个代理配置文件中使用 Git Bash 的绝对路径**(当下即可生效)。 +2. **一个 WSL 包装脚本**,通过 `cmd.exe` 委派给原生的 Windows `teamai` + (在日后 `teamai pull` 把钩子还原成裸 `bash` 时依然有效)。 + +两者都配置好后,`teamai doctor` 会报告六个已安装工具均健康,且每次 +`hook-dispatch` 调用通过两种机制都返回 `exit=0`。 + +--- + +## TeamAI 钩子简介(回顾) + +`teamai hooks inject` 会向每个代理的配置文件中写入类似如下的命令: + +```json +"command": "bash -lc \"teamai hook-dispatch session-start --tool claude 2>/dev/null\" || true" +``` + +每个工具包含六个钩子:`SessionStart`、`Stop`、`PostToolUse`(三个匹配器: +`*`、`Skill`、`TodoWrite`)以及 `UserPromptSubmit`。它们让团队仓库能够记录会话 +统计信息,并在各代理间应用共享的规则 / 技能。 + +--- + +## Windows 上的问题 + +### 故障模式 1 — 裸 `bash` → WSL Node 18 崩溃 + +在 Windows 上,`PATH` 中的裸 `bash` 会解析到 **WSL 启动器** +(`C:\Windows\System32\bash.exe`)。WSL 自带的 Node 是 **v18**,而 TeamAI +打包产物需要更高版本的 Node,因此每次钩子调用都会静默崩溃。由于命令以 `|| true` +结尾,崩溃被吞掉、不记录日志——钩子永不触发,但 `teamai doctor` 仍报告它们 +“存在”。 + +### 故障模式 2 — `hasShell()` 跳过 CodeBuddy / WorkBuddy + +`src/builtin-hooks.ts` 用 `hasShell()` 来门控依赖 shell 的工具: + +```ts +export function hasShell(): boolean { + if (_hasShellCache === undefined) { + try { + _hasShellCache = fs.existsSync('/bin/sh'); + } catch { + _hasShellCache = false; + } + } + return _hasShellCache; +} +``` + +`/bin/sh` 在 Windows 上不存在,因此 `hasShell()` 为 `false`,`skipToolsWithoutShell()` +会把 `codebuddy` / `workbuddy`(`SHELL_DEPENDENT_TOOLS`)加入跳过集合。这两个代理 +在 Windows 上**完全不会获得钩子**,即使其他一切都正常。 + +> 说明:`workbuddy` 有一个局部逃生通道——若 `bundledShellFor(tool)` 找到了 +> WorkBuddy 自带的 PortableGit `sh.exe`,`hasShellFor()` 会返回 `true`。但这仅在 +> 该二进制确实存在时才有用,而 `codebuddy` 没有自带 shell,因此在 Windows 上会被 +> 无条件跳过。 + +--- + +## 根本原因 + +1. **裸 `bash` → WSL Node 18.** Windows 的 `PATH` 会把 `bash` 解析到 WSL 启动器, + 而非 Git Bash;WSL 的 Node 18 无法解析 TeamAI 打包产物。 +2. **`hasShell()` 的 Windows bug.** `fs.existsSync('/bin/sh')` 在 Windows 上永远为假, + 因此跳过 `codebuddy` / `workbuddy` 的钩子注入。 +3. **WSL 路径转换.** 在 WSL 侧用 `/mnt/c/...` 路径 `exec` Windows Node 的包装脚本会被 + 改写成 `C:\mnt\c\...`,导致 `MODULE_NOT_FOUND`。 + +--- + +## 修复方案(用户侧,持久化) + +### 机制 A — 在每个代理配置文件中使用 Git Bash 的绝对路径 + +把每个钩子命令中的裸 `bash` 替换为 Git Bash 的 Windows 绝对路径(若 Git 装在其他 +位置请相应调整): + +```json +"command": "\"C:\\Program Files\\Git\\bin\\bash.exe\" -lc \"teamai hook-dispatch session-start --tool 2>/dev/null\" || true" +``` + +此修改适用于所有带钩子的代理: + +- `~/.claude/settings.json` — 6 个钩子 +- `~/.codex/hooks.json` — 6 个钩子 +- `~/.zcode/cli/config.json` — `command` 字段 → Git Bash 路径;6 个钩子 +- `~/.codebuddy/settings.json` — 若不存在则创建;6 个钩子 +- `~/.qoder/settings.json` — 若不存在则创建;6 个钩子 +- WorkBuddy / Cline / Cursor / OpenCode 等对应配置 + +请用支持 JSON 的编辑器修改(不要用 `sed` 手工改——双引号必须保持转义)。建议为每个 +原文件保留一份 `*.teamai-bak` 备份以便回滚。 + +### 机制 B — WSL 包装脚本(抵御 `teamai pull` 的持久化) + +`teamai pull` / `hooks inject` 会把代理配置重新写回裸 `bash`。机制 A 会被覆盖,但 +WSL 包装脚本能让裸 `bash` 依然可用。在你的 WSL 家目录(如 +`/home//.teamai-wsl/bin/teamai`)创建包装脚本: + +```sh +#!/bin/sh +# 通过 cmd.exe 委派给原生的 Windows teamai(正确的 Node 与路径) +exec cmd.exe /c teamai "$@" +``` + +在 `~/.profile` / `~/.bashrc` 中用一个标记把它加到 `PATH` 前面: + +```sh +# [teamai-wsl-fix] +export PATH="$HOME/.teamai-wsl/bin:$PATH" +``` + +这样,裸 `bash` 钩子会找到 `teamai` → `cmd.exe` → 原生 Windows TeamAI。`cmd.exe` +委派方式完全绕开了 WSL 的 `/mnt/c` 路径转换 bug。**此方案要求 WSL 保持安装。** + +### 让所有工具都完整可用 + +- 在 `~/.teamai/config.yaml` 的 `enabledAgents` 中加入 `qoder` 和 `codebuddy`。 +- 把团队仓库中的技能与规则复制到 `~/.qoder` 和 `~/.codebuddy`,让这些代理不仅接入 + 钩子,而且具备完整能力。 + +--- + +## 验证(全部通过) + +```sh +teamai doctor +``` + +预期:为 **claude、codex、qoder、zcode、codebuddy、workbuddy** 报告钩子存在。 + +按工具分别检查两种方式: + +```sh +# 机制 A(Git Bash 绝对路径) +"C:\Program Files\Git\bin\bash.exe" -lc "teamai hook-dispatch session-start --tool claude 2>/dev/null"; echo $? + +# 机制 B(通过 WSL 包装脚本的裸 bash) +wsl bash -lc "teamai hook-dispatch session-start --tool claude 2>/dev/null"; echo $? +``` + +每个工具通过两种机制都应打印 `0`。 + +```text +doctor: ✔ claude ✔ codex ✔ qoder ✔ zcode ✔ codebuddy ✔ workbuddy +dispatch (Git-Bash 路径): claude=0 codex=0 zcode=0 codebuddy=0 qoder=0 +dispatch (裸 bash/WSL): claude=0 codex=0 zcode=0 codebuddy=0 qoder=0 workbuddy=0 +``` + +--- + +## 限制 / 无法做到的事 + +- **持久化依赖 WSL 包装脚本.** `teamai pull` 会把代理配置还原成裸 `bash`;机制 A 被 + 覆盖,机制 B 仅在 **WSL 保持安装** 时有效。若移除 WSL,裸 `bash` 钩子会再次失效。 +- **机制 B 需要 WSL.** 在没有 WSL 的机器上,只有机制 A(当前配置文件中的 Git Bash + 绝对路径)可用。 +- **不会修补 TeamAI 本身.** 上游的 `hasShell()` bug 与裸 `bash` 默认值并未在 + `teamai-cli` 内部修复。执行 `npm update teamai-cli` 后需重新应用本修复(或依赖 + WSL 包装脚本)。 +- **macOS / Linux 无需修复.** 在这些系统上,裸 `bash` 已解析到系统 Node,原生可用。 +- **`teamai doctor` 的 `gh` 检查可能是误报.** 它可能在没有 `APPDATA` 的情况下启动 + `gh`,因此即使 `gh auth status` 显示已登录,它也看不到登录状态。若其他检查均通过, + 可忽略此项。 +- **会保留备份文件.** 已编辑代理配置的 `*.teamai-bak` 备份会保留作为回滚保险。 + +--- + +## 给维护者的修复建议(上游) + +两处小改动即可让 Windows 开箱即用: + +### 1. 让 `hasShell()` 感知 Windows + +在 Windows 上 `/bin/sh` 不存在,但 Git for Windows(`sh.exe` / `bash.exe`)或 WSL +提供了可用的 POSIX shell。TeamAI 应当检测它们,而不是永远返回 `false`: + +```ts +export function hasShell(): boolean { + if (_hasShellCache === undefined) { + try { + if (process.platform === 'win32') { + // Git for Windows 自带 sh.exe/bash.exe;WSL 也提供 bash。 + // 钩子通过 `bash -lc ...` 启动,因此以下任一存在即可。 + const candidates = [ + 'C:\\Program Files\\Git\\bin\\bash.exe', + 'C:\\Program Files\\Git\\usr\\bin\\sh.exe', + 'C:\\Windows\\System32\\bash.exe', + ]; + _hasShellCache = candidates.some((p) => fs.existsSync(p)) || + whichBash() !== null; + } else { + _hasShellCache = fs.existsSync('/bin/sh'); + } + } catch { + _hasShellCache = false; + } + } + return _hasShellCache; +} +``` + +仅此一项改动即可让 `codebuddy` / `workbuddy` 的钩子在 Windows 上被注入。 + +### 2. 在 Windows 上把 dispatch 命令默认指向 Git Bash 绝对路径 + +`getDispatchCommand()` 硬编码了 `bash -lc "..."`。在 Windows 上这会被解析到 WSL 的 +Node 18 并崩溃。当 `process.platform === 'win32'` 时,应优先使用 Git Bash 的绝对路径 +(或自带的 PortableGit `sh.exe`)。 + +两处改动均向后兼容:macOS/Linux 仍使用 `/bin/sh`,而 Windows 用户将不再需要上面的 +手工绕行方案。 + +--- + +## 故障排查 + +```sh +teamai doctor + +# 按工具分别检查两种方式: +"C:\Program Files\Git\bin\bash.exe" -lc "teamai hook-dispatch session-start --tool claude 2>/dev/null"; echo $? +wsl bash -lc "teamai hook-dispatch session-start --tool claude 2>/dev/null"; echo $? + +# 若某工具的钩子停止触发: +# 1. 确认包装脚本存在: ls ~/.teamai-wsl/bin/teamai +# 2. 确认 ~/.profile 中的 PATH 导出(标记 # [teamai-wsl-fix]) +# 3. 否则重新应用机制 A(在代理配置中使用 Git Bash 绝对路径) +``` + +--- + +## 涉及的文件(典型用户侧布局) + +| 文件 | 改动 | +|------|------| +| `~/.claude/settings.json` | 钩子命令 → Git Bash 绝对路径(备份:`*.teamai-bak`) | +| `~/.codex/hooks.json` | 钩子命令 → Git Bash 绝对路径(备份:`*.teamai-bak`) | +| `~/.zcode/cli/config.json` | `command` 字段 → Git Bash 路径(备份:`*.teamai-bak`) | +| `~/.codebuddy/settings.json` | 若不存在则创建,含 6 个钩子 | +| `~/.qoder/settings.json` | 若不存在则创建,含 6 个钩子 | +| `~/.teamai/config.yaml` | `enabledAgents` += `qoder`、`codebuddy` | +| `~/.qoder/{skills,rules}`、`~/.codebuddy/{skills,rules}` | 复制团队资源 | +| `~/.teamai-wsl/bin/teamai`(Win)+ `/.teamai-wsl/bin/teamai`(WSL) | 持久化包装脚本 | +| `~/.profile`、`~/.bashrc` | PATH 导出(标记 `# [teamai-wsl-fix]`) |