PerFilePromptGenerator: relative filePattern resolves against process.cwd() instead of the config file directory
还没有人认领这个 Issue。
评估
- 难度
- 3/5
- 预计耗时
- 1-2 天
- 新手友好度
- 72/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 冷清
- 技术栈
- typescript
调研方向
Start in src/prompt-generators/per-file.ts, especially PerFilePromptGenerator.generate() and resolveFiles(), then review src/prompt-generators/test/per-file.test.ts. Add coverage for a relative pattern with an explicit basePath and run the per-file tests. Done means config-relative files are found regardless of the invocation directory, with resumed IDs remaining consistent across runs.
由索引模型根据 Issue 内容生成。
描述
Observed behavior
PerFilePromptGenerator accepts a basePath constructor argument used to resolve {{include:...}} macros, and the CLI loader threads the config-file directory through as that basePath. However, filePattern (and excludePatterns) are passed directly to glob() without a cwd option, so a relative filePattern is resolved against process.cwd() rather than the config file directory.
Source: src/prompt-generators/per-file.ts:62-79
constructor(task: PerFileTask, basePath?: string) {
this.#task = task;
this.#basePath = basePath ?? process.cwd();
}
async *generate(loopState: LoopState): AsyncIterable<Prompt> {
const { filePattern, excludePatterns } = this.#task;
const allFiles = await resolveFiles(filePattern, excludePatterns);
// ...
}
And src/prompt-generators/per-file.ts:85-97:
export async function resolveFiles(
filePattern: string,
excludePatterns?: Array<string>,
): Promise<Array<string>> {
const files = await glob(filePattern, {
...(excludePatterns ? { ignore: excludePatterns } : {}),
nodir: true,
});
files.sort();
return files;
}
Note that #basePath is captured but never used inside generate() for the glob call. The glob library defaults its cwd option to process.cwd().
This is inconsistent with the rest of the CLI config loader:
outputDir: resolved against the config file directory (src/util/load-cli-config.ts:226-229, since issue #34).{{include:...}}macros (in prompt templates andclaude-sdksystemPrompt): resolved against the config file directory (src/util/expand-prompt.ts).JsonPromptGenerator.dataFile: explicitlyresolve(basePath, task.dataFile)(src/prompt-generators/json.ts:122-126).
per-file.filePattern is the odd one out.
Expected behavior
A relative filePattern in a CLI JSON config should resolve against the directory containing the config file, the same as outputDir, {{include:...}} macros, and JsonTask.dataFile. A user writing:
{ "promptGenerator": ["per-file", { "filePattern": "src/**/*.ts", "promptTemplate": "Review {{file}}" }] }
in /some/where/config.json naturally expects the loop to enumerate /some/where/src/**/*.ts, not ${cwd}/src/**/*.ts.
Minimal reproduction
mkdir -p /tmp/llt-pf-repro/proj/src
cat > /tmp/llt-pf-repro/proj/src/hello.ts <<'TS'
export const hello = 'world';
TS
cat > /tmp/llt-pf-repro/proj/config.json <<'JSON'
{
"name": "demo",
"agent": "claude-sdk",
"promptGenerator": [
"per-file",
{ "filePattern": "src/**/*.ts", "promptTemplate": "Review {{file}}" }
]
}
JSON
mkdir -p /tmp/llt-pf-repro/elsewhere
cd /tmp/llt-pf-repro/elsewhere
pnpx loop-the-loop --dry-run /tmp/llt-pf-repro/proj/config.json
# Yields zero prompts: glob looks for /tmp/llt-pf-repro/elsewhere/src/**/*.ts.
# Expected: one prompt for src/hello.ts, since the config lives next to src/.
For comparison, running the same command from /tmp/llt-pf-repro/proj does match the file, because process.cwd() happens to coincide with the config directory in that case.
Suggested fix
Thread #basePath through to glob's cwd option:
export async function resolveFiles(
filePattern: string,
excludePatterns?: Array<string>,
cwd?: string,
): Promise<Array<string>> {
const files = await glob(filePattern, {
...(cwd ? { cwd } : {}),
...(excludePatterns ? { ignore: excludePatterns } : {}),
nodir: true,
});
files.sort();
return files;
}
and in generate():
const allFiles = await resolveFiles(filePattern, excludePatterns, this.#basePath);
glob's cwd option is a no-op when the pattern is already absolute, so callers that pass absolute paths (including the existing tests in src/prompt-generators/__test__/per-file.test.ts) keep working. A new test should cover the relative case with an explicit basePath.
One subtlety: with cwd set, glob returns paths relative to cwd. The current id (used by LoopState) is whatever glob returns. If we want IDs to remain stable across runs regardless of the invocation cwd, the fix should also normalize the returned paths (e.g. by resolving to absolute, or by joining with basePath) so that the resumed IDs match a fresh run from a different directory.
- 主要语言
- TypeScript
- 星标
- 2
- 派生
- 1
- PR 合并指标
- 30 天内没有已合并 PR
环境准备
这个项目没有提供开发容器、Dockerfile 或贡献指南,环境需要你自己搭建:先看它的 README,通用步骤见我们的新手贡献指南。
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
joewalker/loop-the-loop 的其他 Issue
-
bug S4
难度 2/5 1-3 小时 新手友好度 75/100
joewalker/loop-the-loop#88 ·
-
Git exec(): child killed by a signal rejects with new Error('') and loses the signal information未关闭bug S3
难度 2/5 1-3 小时 新手友好度 82/100
joewalker/loop-the-loop#84 ·
-
bug S3
难度 2/5 1-3 小时 新手友好度 78/100
joewalker/loop-the-loop#83 ·
-
bug S3
难度 2/5 1-3 小时 新手友好度 76/100
joewalker/loop-the-loop#82 ·
-
bug S4
难度 1/5 1 小时以内 新手友好度 90/100
joewalker/loop-the-loop#79 ·
查看 joewalker/loop-the-loop 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 66/100
维护者通常 2 天内回复
-
reproduced
难度 2/5 1-3 小时 新手友好度 74/100
anomalyco/opencode#62052 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
strapi/design-system#2084 ·
维护者通常 3 天内回复
-
check:passed streams:remove
难度 1/5 1 小时以内 新手友好度 67/100
维护者通常 1 天内回复
-
OAuth documentation for GET /api/v2/users/me/ appears inconsistent with required global read scope未关闭
难度 2/5 1-3 小时 新手友好度 68/100
维护者通常 1 天内回复