mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-02 11:45:20 +02:00
a64d70ba35
Rebumped v1.8.0.0 -> v1.11.0.0 (minor-past main's v1.10.1.0) using bin/gstack-next-version — the same queue-aware path this branch introduces. CHANGELOG repositioned so v1.11.0.0 sits above main's new entries (v1.10.1.0 / v1.10.0.0 / v1.9.0.0). Conflicts resolved: - VERSION, package.json: rebumped to v1.11.0.0 (util-picked) - bin/gstack-config: merged both lists (workspace_root + gbrain keys) - CHANGELOG.md: hoisted v1.11.0.0 entry above main's new entries Pre-existing failures in main (4) documented but not fixed in this PR: 1. gstack-brain-sync secret scan > blocks bearer-json (brain-sync tests) 2. no files larger than 2MB (security-bench fixture, already TODO'd) 3. selectTests > skill-specific change (touchfiles scoping) 4. Opus 4.7 overlay pacing directive (expectation stale after v1.10.1.0 removed the Fan out nudge) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
61 lines
2.2 KiB
TypeScript
61 lines
2.2 KiB
TypeScript
/**
|
|
* Model overlay resolver — reads model-overlays/{model}.md and returns it
|
|
* wrapped in a subordinate behavioral-patch section.
|
|
*
|
|
* Precedence:
|
|
* 1. Exact match: ctx.model === 'gpt-5.4' → reads model-overlays/gpt-5.4.md
|
|
* 2. INHERIT directive: if the file's first non-whitespace line is
|
|
* `{{INHERIT:claude}}`, the resolver reads model-overlays/claude.md first
|
|
* and concatenates it ahead of the rest of this file's content.
|
|
* This lets `gpt-5.4.md` build on top of `gpt.md` without duplication.
|
|
* 3. Missing file: returns empty string (graceful degradation, no error).
|
|
* 4. No ctx.model set: returns empty string.
|
|
*
|
|
* The returned block is subordinate to skill workflow, safety gates, and
|
|
* AskUserQuestion instructions. The subordination language is part of the
|
|
* wrapper heading so it appears with every overlay regardless of file content.
|
|
*/
|
|
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import type { TemplateContext } from './types';
|
|
|
|
const OVERLAY_DIR = path.resolve(import.meta.dir, '../../model-overlays');
|
|
|
|
const INHERIT_RE = /^\s*\{\{INHERIT:([a-z0-9-]+(?:\.[0-9]+)*)\}\}\s*\n/;
|
|
|
|
export function readOverlay(model: string, seen: Set<string> = new Set()): string {
|
|
if (seen.has(model)) return ''; // cycle guard
|
|
seen.add(model);
|
|
|
|
const filePath = path.join(OVERLAY_DIR, `${model}.md`);
|
|
if (!fs.existsSync(filePath)) return '';
|
|
|
|
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
const match = raw.match(INHERIT_RE);
|
|
if (!match) return raw.trim();
|
|
|
|
const baseModel = match[1];
|
|
const base = readOverlay(baseModel, seen);
|
|
const rest = raw.replace(INHERIT_RE, '').trim();
|
|
|
|
if (!base) return rest;
|
|
return `${base}\n\n${rest}`;
|
|
}
|
|
|
|
export function generateModelOverlay(ctx: TemplateContext): string {
|
|
if (!ctx.model) return '';
|
|
|
|
const content = readOverlay(ctx.model);
|
|
if (!content) return '';
|
|
|
|
return `## Model-Specific Behavioral Patch (${ctx.model})
|
|
|
|
The following nudges are tuned for the ${ctx.model} model family. They are
|
|
**subordinate** to skill workflow, STOP points, AskUserQuestion gates, plan-mode
|
|
safety, and /ship review gates. If a nudge below conflicts with skill instructions,
|
|
the skill wins. Treat these as preferences, not rules.
|
|
|
|
${content}`;
|
|
}
|