Skip to content

fix: 修复 OPENSPEC_DIR 环境变量读取及路径函数不一致 (closes #2)#3

Merged
devcxl merged 7 commits into
masterfrom
fix/issue-2-env-var-and-path-consistency
Jun 12, 2026
Merged

fix: 修复 OPENSPEC_DIR 环境变量读取及路径函数不一致 (closes #2)#3
devcxl merged 7 commits into
masterfrom
fix/issue-2-env-var-and-path-consistency

Conversation

@devcxl

@devcxl devcxl commented Jun 12, 2026

Copy link
Copy Markdown
Owner

变更说明

修复两个代码审查发现的问题:

1. OPENSPEC_DIR 环境变量只写不读

src/plugin/server.tsprocess.env.OPENSPEC_DIR 仅被写入,但核心模块 src/util/paths.tsopenspecRoot() 使用模块级变量 _openspecDir,从不读取环境变量。README 声明的功能未实现。

修复:在 createOpencodeSpec() 入口处、options 检查之前,先检查 process.env.OPENSPEC_DIR 并调用 setOpenspecDir()

优先级链:env > options > config > default

2. design.ts / tasks.ts 硬编码路径

design.tstasks.ts 使用 path.join(targetDir, "design.md") / path.join(targetDir, "tasks.md") 硬编码文件名,而 src/util/paths.ts 中已定义 designPath()tasksPath() 函数(proposal.ts 已正确使用 proposalPath())。

修复:统一使用 designPath() / tasksPath() 函数生成路径。

关联 Issue

Closes #2

Agent Brief 验收标准对照

  • 设置 OPENSPEC_DIR 环境变量后,getOpenspecDir() 返回环境变量指定的值
  • 环境变量优先级高于 options.directory 和 config.openspec.directory
  • 未设置环境变量时,options.directory 和 config.openspec.directory 正常生效
  • 环境变量、options、config 均未设置时,使用默认值 "openspec"
  • design.ts 使用 designPath() 函数生成路径
  • tasks.ts 使用 tasksPath() 函数生成路径
  • 所有测试通过(基线 60/62 → 63/65,2 个 reference-scripts 失败为已有问题)
  • 无回归

变更文件

文件 变更类型
src/plugin/server.ts 修改 - 添加 env var 读取
src/core/artifact/design.ts 修改 - 使用 designPath()
src/core/artifact/tasks.ts 修改 - 使用 tasksPath()
test/plugin.test.ts 修改 - 新增 3 个测试
docs/2026-06-13-issue-2-fix-env-var-paths-brief.md 新增 - Agent Brief 归档
docs/diagnosis-issue-2.md 新增 - 诊断报告归档

验证

  • 测试全部通过(63/65, 2 个 reference-scripts 失败为已有问题)
  • 无越界修改
  • 无回归

devcxl added 6 commits June 12, 2026 19:39
优先级链:env > options > config > default

- server.ts: 在 createOpencodeSpec() 入口处先读取 process.env.OPENSPEC_DIR
- options.directory 仅在 env var 未设置时才调用 setOpenspecDir
- test/plugin.test.ts: 添加环境变量读取测试,afterEach 清理 env var 防止泄漏
验证 env > options > config 优先级链:
- env var 与 options.directory 同时设置时 env var 胜出
- env var 与 config.openspec.directory 同时设置时 env var 胜出
将硬编码 path.join(targetDir, 'design.md') 替换为 designPath(input.projectDir, slug)
移除不再需要的 node:path import
将硬编码 path.join(targetDir, 'tasks.md') 替换为 tasksPath(input.projectDir, slug)
移除不再需要的 node:path import
@devcxl devcxl added the bug Something isn't working label Jun 12, 2026

@devcxl devcxl left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查报告 — PR #3 (fix/issue-2-env-var-and-path-consistency)

[CRITICAL] process.env.OPENSPEC_DIR 在 options.directory 设置时被静默覆盖

文件: src/plugin/server.ts:31
问题: 当环境变量已设置时,options.directory 的处理逻辑仍然会无条件执行 process.env.OPENSPEC_DIR = dir(第 31 行),导致环境变量被覆盖。虽然 _openspecDir 模块变量保持正确(getOpenspecDir() 返回 env-wins),但 process.env.OPENSPEC_DIR 变成了 options-dir。技能参考脚本 assets/skills/_shared/references/openspec.js 直接读取 process.env.OPENSPEC_DIR,会拿到错误的值。

当前代码:

if (options?.directory && typeof options.directory === "string" && options.directory.trim()) {
    const dir = options.directory.trim()
    if (!process.env.OPENSPEC_DIR?.trim()) {
        setOpenspecDir(dir)
    }
    process.env.OPENSPEC_DIR = dir  // ← BUG: 无条件覆盖环境变量
}

修复方案:process.env.OPENSPEC_DIR = dir 移入同一个 guard 内:

if (options?.directory && typeof options.directory === "string" && options.directory.trim()) {
    const dir = options.directory.trim()
    if (!process.env.OPENSPEC_DIR?.trim()) {
        setOpenspecDir(dir)
        process.env.OPENSPEC_DIR = dir
    }
}

验证方法: 在测试中增加对 process.env.OPENSPEC_DIR 的断言:

it("环境变量优先级高于 options.directory 且 env var 不被覆盖", async () => {
    process.env.OPENSPEC_DIR = "env-wins"
    try {
        await OpencodeSpec(ctx, { directory: "options-dir" })
        expect(getOpenspecDir()).toBe("env-wins")
        expect(process.env.OPENSPEC_DIR).toBe("env-wins")  // ← 当前会失败
    } finally {
        delete process.env.OPENSPEC_DIR
    }
})

[WARNING] config 钩子中的 guard 使用硬编码字符串 "openspec"

文件: src/plugin/server.ts:45
问题: if (getOpenspecDir() === "openspec") 将默认值与字面量 "openspec" 耦合。如果 src/util/paths.ts 中的默认值被修改,这个 guard 会静默失效。

建议: 提取默认值为常量(如 DEFAULT_OPENSPEC_DIR),供 server.ts 引用。但这是预存问题,非本次 PR 引入,可作为后续优化。


[SUGGESTION] 测试未覆盖 options.directory > config.openspec.directory 优先级

文件: test/plugin.test.ts
问题: 新增的 3 个测试覆盖了 env var 优先级的三个场景,但缺少以下测试:

  • options.directory 优先级高于 config.openspec.directory(无环境变量时)
  • config.openspec.directory 单独生效(无环境变量、无 options 时)

建议补充以完整覆盖优先级链。


[SUGGESTION] design.ts / tasks.tstargetDir 变量与 filePath 存在冗余计算

文件: src/core/artifact/design.ts:17-18src/core/artifact/tasks.ts:18-19
问题: targetDir = changeDir(...)filePath = designPath(...) 内部都调用了 slugify()changeDir(),存在重复计算。targetDir 等价于 path.dirname(filePath)。微小优化,不影响正确性。


逐条验收标准检查

验收标准 状态 说明
设置 OPENSPEC_DIRgetOpenspecDir() 返回环境变量值 测试通过
环境变量优先级高于 options.directory ⚠️ getOpenspecDir() 正确,但 process.env.OPENSPEC_DIR 被覆盖(CRITICAL)
环境变量优先级高于 config.openspec.directory 测试通过
未设置时 options.directory / config 正常生效 已有测试覆盖
均未设置时使用默认值 "openspec" 已有测试覆盖
design.ts 使用 designPath() 已正确替换
tasks.ts 使用 tasksPath() 已正确替换
所有测试通过 63/65 passed(2 个 reference-scripts 失败为已有问题)
无回归 基线测试全部通过
无越界修改 仅修改了 Issue 范围内的文件

审查结论

🔴 Request Changes — 存在 1 个 CRITICAL 问题:process.env.OPENSPEC_DIR 在 options.directory 设置时被静默覆盖,导致技能参考脚本读取到错误的目录名。

修复该问题后,其余变更质量良好:路径替换正确、测试覆盖充分、无越界修改。

CRITICAL: 将 process.env.OPENSPEC_DIR = dir 移入 env var 守卫内,
确保环境变量设置后不会被 options/config 覆盖。
同时补充 process.env.OPENSPEC_DIR 断言测试。

@devcxl devcxl left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查结论:✅ 通过(Approve)

上一次审查发现的 CRITICAL 问题已正确修复,无新增 Critical/High 问题。


修复确认

CRITICAL #1process.env.OPENSPEC_DIRoptions.directory 无条件覆盖

✅ 已修复。src/plugin/server.ts 新增了环境变量优先读取逻辑,优先级链 env > options > config > default 正确实现:

  • 第 21-24 行:启动时先读取 process.env.OPENSPEC_DIR 并调用 setOpenspecDir()
  • 第 28 行:options.directory 仅在 !process.env.OPENSPEC_DIR?.trim() 时才生效
  • 第 45/49 行:config.openspec.directory 同样受 env 保护

CRITICAL #2design.ts / tasks.ts 硬编码路径

✅ 已修复。两个文件均改用 designPath() / tasksPath(),同时清理了不再需要的 import path from "node:path"


测试结果

Test Files  1 failed | 9 passed (10)
     Tests  2 failed | 63 passed (65)
  • 3 个新增测试全部通过
  • 2 个失败是已有的 reference-scripts 测试(mark-tasks / archive),非本次引入
  • TypeScript 类型检查(tsc --noEmit)通过

发现的问题

[MEDIUM] config 钩子中缺少 config.openspec.directory 独立生效的测试

test/plugin.test.ts 中新增的 3 个测试覆盖了 env 优先级场景,但缺少 config.openspec.directory 在无 env 时独立生效的测试用例。这是已有测试覆盖缺口,非本次引入。

[SUGGESTION] envDir 变量命名

src/plugin/server.ts:21const envDir = process.env.OPENSPEC_DIR?.trim() — 变量名 envDir 暗示是目录路径,实际只是目录名(如 "openspec")。不过与代码库其他位置的命名风格一致,无需修改。

@devcxl
devcxl merged commit 3aaffb3 into master Jun 12, 2026
1 check passed
@devcxl
devcxl deleted the fix/issue-2-env-var-and-path-consistency branch June 12, 2026 18:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

修复 OPENSPEC_DIR 环境变量读取逻辑及路径函数不一致

1 participant