PerFilePromptGenerator: relative filePattern resolves against process.cwd() instead of the config file directory
まだ誰も着手していません。
評価
- 難易度
- 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 にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- 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
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
awslabs/visual-asset-management-system#804 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
restatedev/sdk-typescript#813 ·
-
bug desktop P1 session XS
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
Merit-Systems/x402scan#1312 ·
-
type:bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
Azure/apiops-cli#331 ·
メンテナーはふだん 3 日以内に返信