feat: add phase 3 prompt customization backend

- parse prompt model and argument-hint metadata and persist model on prompt invocations
- expand markdown-linked file context in scanned prompt and instruction bodies
- discover .claude/rules instructions and support Claude-style paths metadata
- discover customization roots up to the nearest parent repository and watch them for changes
- apply per-turn prompt model overrides before sidecar execution

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-04-02 12:21:59 +02:00
co-authored by Copilot
parent bcbdd2ef29
commit 6eadb36c10
17 changed files with 779 additions and 114 deletions
@@ -38,6 +38,25 @@ describe('ProjectCustomizationWatcher', () => {
]);
});
test('includes parent repository roots when the project is nested inside a monorepo', async () => {
const repoRoot = await createTempDirectory();
const projectPath = join(repoRoot, 'packages', 'frontend');
await mkdir(join(repoRoot, '.git'), { recursive: true });
await mkdir(join(projectPath, 'src'), { recursive: true });
await mkdir(join(repoRoot, '.github', 'prompts'), { recursive: true });
await mkdir(join(repoRoot, '.claude', 'rules'), { recursive: true });
expect(await collectProjectCustomizationWatchPaths(projectPath)).toEqual([
join(repoRoot, '.claude'),
join(repoRoot, '.claude', 'rules'),
join(repoRoot, '.github'),
join(repoRoot, '.github', 'prompts'),
join(repoRoot, 'packages'),
projectPath,
repoRoot,
].sort((left, right) => left.localeCompare(right)));
});
test('debounces change notifications and closes watches when projects are removed', async () => {
const changeCalls: string[] = [];
const closeByPath = new Map<string, ReturnType<typeof mock>>();