Tencent / Tencent/teamai-cli

[bug] Windows: env 注入到 shell profile 时写的是原生路径,source 静默失败而 doctor 仍报通过

Open
#661 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
4.8k
Forks
342
Avg merge
13h 48m
Merged PRs (30d)
211

Description

English summary — On Windows, the env block injected into ~/.bashrc contains
[ -f C:\Users\<user>\.teamai/env.sh ] && source C:\Users\<user>\.teamai/env.sh.
Because an unquoted \ is an escape character in POSIX shells, the word degrades to
C:UsersCarlos.teamai/env.sh, the [ -f ] test is false, && short-circuits and
source never runs — so no env variable is ever delivered. teamai doctor still
prints ✔ Env variables injected in shell profile because the check only greps for the
marker comment. The only visible symptom is downstream: MCP entries using ${VAR} get
skipped with unresolved variable(s).

Description

Windows 上 teamai pull(或 teamai init)注入到 shell profile 的 env 块,source 行用的是原生 Windows 路径(反斜杠)

# [teamai:env:start]
# DO NOT EDIT: This section is auto-managed by teamai
[ -f C:\Users\<user>\.teamai/env.sh ] && source C:\Users\<user>\.teamai/env.sh
# [teamai:env:end]

在没有引号的 POSIX shell 词里,\ 是转义符。上面这一行实际被解析成:

+ '[' -f C:UsersCarlos.teamai/env.sh ']'
exit=1

反斜杠被吞掉,得到一个不可能存在的路径 → [ -f ... ] 为假 → && 短路 → source 从未执行。于是 ~/.teamai/env.sh 里的变量永远进不了任何 shell。

.bashrc 里一个失败的 [ 测试既不报错也不中断,所以从用户视角完全静默:没有任何输出、没有非零退出影响会话。

更糟的是 teamai doctor 仍然显示通过:

✔ Env variables injected in shell profile

因为该检查只断言 profile 文本里出现过标记串 # [teamai:env:start],从不验证这个块是否真的能加载。于是失败被掩盖,唯一的可见症状跑到下游去了——MCP 定义里引用 ${VAR} 的服务被跳过,输出一句 unresolved variable(s),完全指不到 env.yaml 或 shell profile 头上。

Root cause

generateShellBlock()path.join() 的结果(win32 → 反斜杠)原样插进 shell 脚本:

generateShellBlock(teamaiHome) {
  const lines = [
    TEAMAI_ENV_START,
    "# DO NOT EDIT: This section is auto-managed by teamai",
    `[ -f ${teamaiHome}/env.sh ] && source ${teamaiHome}/env.sh`,
    TEAMAI_ENV_END
  ];
  return lines.join("\n");
}

teamaiHome 来自 getDataHome()getTeamaiHome(),即 path.join(home, ".teamai"),在 Windows 上必然是 C:\Users\<user>\.teamai。这里既没有换成分隔符、也没有加引号。

配套的 doctor 检查只做字符串包含判断:

{
  name: "Env variables injected in shell profile",
  check: async () => {
    if (teamConfig?.sharing?.env?.injectShellProfile === false) return true;
    if (!localConfig) return true;
    const envYamlPath = path.join(localConfig.repo.localPath, "env", "env.yaml");
    if (!await pathExists(envYamlPath)) return true;
    const home = getUserHome();
    // ...
    return content?.includes(TEAMAI_ENV_START) ?? false;
  },
  fix: "Run `teamai pull` to inject env variables into shell profile"
}

整条链路里没有任何一步做「目标 shell 需要什么形式的路径」这个转换或校验。

Reproduction

  1. Windows 11 + Node.js + teamai 0.24.0,团队仓库含 env/env.yaml 且至少有一个变量。
  2. teamai pull → 上面的反斜杠块写入 ~/.bashrc
  3. sh -x 跑这个块:
$ sh -x ~/.bashrc          # 或单独把该块存成文件后执行
+ '[' -f C:UsersCarlos.teamai/env.sh ']'
exit=1
  1. 确认变量从未到达 shell:
$ bash -lc 'echo "MY_VAR=[${MY_VAR}]"'
MY_VAR=[]
  1. teamai doctor → 依旧 ✔ Env variables injected in shell profile

对照:同一个块用 POSIX 形式写就能工作(这是我本机临时修正后的形态):

# [teamai:env:start]
# DO NOT EDIT: This section is auto-managed by teamai
[ -f "/c/Users/Carlos/.teamai/env.sh" ] && source "/c/Users/Carlos/.teamai/env.sh"
# [teamai:env:end]
$ bash -lc 'source ~/.bashrc >/dev/null 2>&1; echo "len=${#MY_VAR}"'
len=16

Environment

  • OS: Windows 11 25H2 (10.0.26200)
  • Node.js: v22.22.2v22.17.0 同样复现)
  • teamai: 0.24.0
  • Provider: GitHub
  • AI tool(s): WorkBuddy / CodeBuddy —— 注意本缺陷与具体工具无关,只要 profile 是 POSIX shell(~/.bashrc~/.zshrc)就会中招

Suggested fix

两处独立的小改动,建议都做:

  1. 输出 shell 安全的路径。 在生成块的地方做转换,而不是改 path 的计算结果(同一个值还要用于真实文件系统访问)。推荐直接回避绝对路径,用 $HOME 并加引号:

    [ -f "$HOME/.teamai/env.sh" ] && source "$HOME/.teamai/env.sh"
    

    如果需要绝对路径(例如 dataHome 被自定义到别的盘),则应转成目标 shell 能懂的形式(/c/Users/... 这类 MSYS 风格)并始终加引号——注意 Program Files 这种带空格的路径只有加引号才安全。

  2. doctor 验证行为而不是验证存在。 现在只要字符串在就算通过。建议在 shell 里真正 source 一次 profile(或至少求值那个 [ -f ... ] 测试)并断言其中一个变量确实解析成功,否则报 .bashrc 中的 env 块无法加载

Logs

~/.bashrc 中被注入的块,以及它的求值结果
$ grep -A3 'teamai:env:start' ~/.bashrc
# [teamai:env:start]
# DO NOT EDIT: This section is auto-managed by teamai
[ -f C:\Users\Carlos\.teamai/env.sh ] && source C:\Users\Carlos\.teamai/env.sh
# [teamai:env:end]

$ sh -x <把上面的块存成文件后执行>
+ '[' -f C:UsersCarlos.teamai/env.sh ']'
exit=1

即:source 分支根本没被走到。

teamai doctor 的假通过
$ teamai doctor
✔ Env variables injected in shell profile

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at generateShellBlock(), where teamaiHome is inserted into the shell profile, and inspect the doctor check named "Env variables injected in shell profile". Reproduce the generated block on Windows with sh -x or bash, then verify that the environment variable loads and doctor does not report success for an unusable block.

Written by the indexing model from the issue text.

Assessment

Tech stack
bash, node.js, typescript
Domain
cli, developer-experience
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.