fix(skills): Done-means list leaves out steps a host suppresses and allows the small-diff skip (review fix round)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-11-03 02:38:30 +00:00
1 parent ebbe8a24b5
commit 7384ca0d48
5 files changed
+36 -17

No files matched your search

+12 -3
View File
@@ -9,6 +9,7 @@
import * as fs from 'fs';
import * as path from 'path';
import type { TemplateContext } from './types';
import { getHostConfig } from '../../hosts/index';
const ROOT = path.resolve(import.meta.dir, '..', '..');
const code = (s: string) => '\u0060' + s + '\u0060';
@@ -31,6 +32,12 @@ const KIND_FIELDS: Record<ContractItem['kind'], string[]> = {
agent_dispatch: ['match'],
};
// The resolver that renders the step each kind checks today. A host that suppresses it never shows that step, so its items are left out of the list there.
const BACKED_BY: Partial<Record<ContractItem['kind'], string>> = {
selected_specialists_dispatched: 'REVIEW_ARMY',
agent_dispatch: 'ADVERSARIAL_STEP',
};
const PLACEHOLDER = /^\[.*\]$|^<.*>$|^\.\.\.$|^(todo|tbd|n\/a)$/i;
function fail(where: string, problem: string): never {
@@ -101,12 +108,13 @@ function plainWords(item: ContractItem): string {
switch (item.kind) {
case 'report_labels': return 'a ' + code(item.heading) + ' with ' + list(item.labels) + ' filled in';
case 'check_after_last_edit': return 'a test or repro command run after your last edit';
case 'selected_specialists_dispatched': return 'the specialist selection printed (' + code(item.marker) + ' ...), then one Agent dispatch per specialist it names';
case 'selected_specialists_dispatched': return 'the specialist selection printed (' + code(item.marker) + ' ...), then one Agent dispatch per specialist it names (none when a small diff skips them)';
case 'agent_dispatch': return 'an Agent dispatch for the ' + item.id.replace(/-/g, ' ') + ', its prompt including "' + item.match + '"';
}
}
export function renderDoneMeans(contract: SkillContract): string {
if (contract.items.length === 0) return '';
return [
'## Done means',
'',
@@ -121,6 +129,7 @@ export function renderDoneMeans(contract: SkillContract): string {
export function generateContractDoneMeans(ctx: TemplateContext): string {
const where = path.relative(ROOT, ctx.tmplPath).split(path.sep).join('/');
const contract = contractFromTemplate(fs.readFileSync(ctx.tmplPath, 'utf-8'), where, { required: true });
return renderDoneMeans(contract!);
const contract = contractFromTemplate(fs.readFileSync(ctx.tmplPath, 'utf-8'), where, { required: true })!;
const suppressed = new Set(getHostConfig(ctx.host).suppressedResolvers ?? []);
return renderDoneMeans({ ...contract, items: contract.items.filter(item => !suppressed.has(BACKED_BY[item.kind] ?? '')) });
}