Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

PerFilePromptGenerator: relative filePattern resolves against process.cwd() instead of the config file directory

オープン
#64 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
静か
技術スタック
typescript
領域
cli, tooling

調査の方向性

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 の本文から書いたものです。

説明

bug S3

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:

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 を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

joewalker/loop-the-loop のほかの issue

joewalker/loop-the-loop の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。