fix(workspace-context): reconcile resumed baselines

This commit is contained in:
fz
2026-08-04 23:11:15 +08:00
parent 01fa4ceb6e
commit 119c55e35e
16 changed files with 463 additions and 51 deletions

View File

@@ -46,12 +46,14 @@ interface DiscoverOptions {
projectRootMarkers?: string[]
instructionFileCandidates?: string[]
localInstructionFileCandidates?: string[]
projectRoot?: string
signal?: AbortSignal
}
interface LoadOptions extends DiscoverOptions {
maxBytes: number
maxSourceBytes?: number
replacePreviousBaseline?: boolean
}
/** Rendered baseline plus the files that survived byte budgeting. */
@@ -286,7 +288,8 @@ async function discoverInstructionFiles(
}
const cwd = resolve(options.cwd)
const projectRoot = await findProjectRoot(cwd, config.projectRootMarkers, fileSystem, options.signal)
const projectRoot = options.projectRoot
?? await findProjectRoot(cwd, config.projectRootMarkers, fileSystem, options.signal)
for (const dir of ancestorChain(projectRoot, cwd)) {
for (const candidates of [config.instructionFileCandidates, config.localInstructionFileCandidates]) {
for (const file of await allExistingInstructionFiles(dir, projectRoot, candidates, fileSystem, options.signal)) {
@@ -389,7 +392,7 @@ export async function loadBaselineInstructions(
* Load a baseline together with the files retained after rendering.
* @param options - discovery, source-size, byte-budget, and cancellation configuration.
* @param fileSystem - optional provider used instead of host filesystem reads.
* @returns rendered context and retained files, or undefined when empty or disabled.
* @returns rendered context and retained files, an explicit empty replacement set, or undefined when empty or disabled.
*/
export async function loadBaselineInstructionSet(
options: LoadOptions,
@@ -412,8 +415,22 @@ export async function loadBaselineInstructionSet(
}
}
const deduped = dedupInstructionFilesByDirectory(loaded)
if (deduped.length === 0) return undefined
const rendered = renderWorkspaceContext(deduped, { maxBytes: config.maxBytes })
if (deduped.length === 0) {
if (options.replacePreviousBaseline !== true) return undefined
return {
rendered: renderWorkspaceContext([], {
maxBytes: config.maxBytes,
replacePreviousBaseline: true,
}),
included: [],
}
}
const rendered = renderWorkspaceContext(deduped, {
maxBytes: config.maxBytes,
...options.replacePreviousBaseline === undefined
? {}
: { replacePreviousBaseline: options.replacePreviousBaseline },
})
const omitted = new Set(rendered.omitted.map(file => file.absolutePath))
return { rendered, included: deduped.filter(file => !omitted.has(file.absolutePath)) }
}