mirror of https://github.com/garrytan/gstack.git
feat(brain): gen-skill-docs respects gbrain-detection override
Adds --respect-detection flag (and bun run gen:skill-docs:user script). When the flag is set, gen-skill-docs reads ~/.gstack/gbrain-detection.json and filters GBRAIN_CONTEXT_LOAD + GBRAIN_SAVE_RESULTS out of each host's suppressedResolvers when gbrain_local_status is "ok". When absent or gbrain isn't detected, suppression behaves as before. The default `bun run gen:skill-docs` (CI canonical) ignores the detection file so the committed SKILL.md stays reproducible regardless of any developer's local gbrain installation state. Use gen:skill-docs:user for user-local installs (./setup invokes it). No host config files modified — the static suppressedResolvers stay correct for the no-gbrain case; the override happens at gen-time. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
7939269bae
commit
748047f847
|
|
@ -14,6 +14,7 @@
|
|||
"dev:make-pdf": "bun run make-pdf/src/cli.ts",
|
||||
"dev:design": "bun run design/src/cli.ts",
|
||||
"gen:skill-docs": "bun run scripts/gen-skill-docs.ts",
|
||||
"gen:skill-docs:user": "bun run scripts/gen-skill-docs.ts --respect-detection",
|
||||
"dev": "bun run browse/src/cli.ts",
|
||||
"server": "bun run browse/src/server.ts",
|
||||
"test": "bun test browse/test/ test/ make-pdf/test/ --ignore 'test/skill-e2e-*.test.ts' --ignore test/skill-llm-eval.test.ts --ignore test/skill-routing-e2e.test.ts --ignore test/codex-e2e.test.ts --ignore test/gemini-e2e.test.ts && (bun run slop:diff 2>/dev/null || true)",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,49 @@ import type { HostConfig } from './host-config';
|
|||
const ROOT = path.resolve(import.meta.dir, '..');
|
||||
const DRY_RUN = process.argv.includes('--dry-run');
|
||||
|
||||
// ─── GBrain Detection Override ──────────────────────────────
|
||||
// When --respect-detection is passed, read ~/.gstack/gbrain-detection.json
|
||||
// and un-suppress GBRAIN_CONTEXT_LOAD + GBRAIN_SAVE_RESULTS for hosts that
|
||||
// statically suppress them (claude, codex, slate, factory, opencode,
|
||||
// openclaw, cursor, kiro). Detection state is produced by
|
||||
// bin/gstack-gbrain-detect and persisted by `gstack-config gbrain-refresh`
|
||||
// or by ./setup.
|
||||
//
|
||||
// Default (no flag): static suppressedResolvers honored as-is. Used by
|
||||
// `bun run gen:skill-docs` (CI + canonical checked-in SKILL.md files) so
|
||||
// the committed output is reproducible regardless of any developer's
|
||||
// local gbrain installation state. Use `bun run gen:skill-docs:user`
|
||||
// (which adds --respect-detection) for user-local installs.
|
||||
const RESPECT_DETECTION = process.argv.includes('--respect-detection');
|
||||
|
||||
function loadGbrainOverride(): { detected: boolean } {
|
||||
if (!RESPECT_DETECTION) return { detected: false };
|
||||
const stateDir = process.env.GSTACK_HOME || path.join(process.env.HOME || '', '.gstack');
|
||||
const detectionPath = path.join(stateDir, 'gbrain-detection.json');
|
||||
try {
|
||||
const json = JSON.parse(fs.readFileSync(detectionPath, 'utf-8')) as { gbrain_local_status?: string };
|
||||
return { detected: json.gbrain_local_status === 'ok' };
|
||||
} catch {
|
||||
return { detected: false };
|
||||
}
|
||||
}
|
||||
|
||||
const GBRAIN_OVERRIDE = loadGbrainOverride();
|
||||
|
||||
/**
|
||||
* Compute effective suppressedResolvers for a host, applying the gbrain
|
||||
* detection override when enabled. When the override fires, GBRAIN_*
|
||||
* resolvers are removed from the suppression set so they render in the
|
||||
* generated SKILL.md.
|
||||
*/
|
||||
function effectiveSuppressedResolvers(hostConfig: HostConfig): Set<string> {
|
||||
let list = hostConfig.suppressedResolvers || [];
|
||||
if (GBRAIN_OVERRIDE.detected) {
|
||||
list = list.filter(r => r !== 'GBRAIN_CONTEXT_LOAD' && r !== 'GBRAIN_SAVE_RESULTS');
|
||||
}
|
||||
return new Set(list);
|
||||
}
|
||||
|
||||
// ─── Host Detection (config-driven) ─────────────────────────
|
||||
|
||||
const HOST_ARG = process.argv.find(a => a.startsWith('--host'));
|
||||
|
|
@ -631,9 +674,12 @@ function processTemplate(tmplPath: string, host: Host = 'claude'): { outputPath:
|
|||
const ctx: TemplateContext = { skillName, tmplPath, benefitsFrom, host, paths: HOST_PATHS[host], preambleTier, model: MODEL_ARG_VAL, interactive, explainLevel: EXPLAIN_LEVEL };
|
||||
|
||||
// Replace placeholders (supports parameterized: {{NAME:arg1:arg2}})
|
||||
// Config-driven: suppressedResolvers return empty string for this host
|
||||
// Config-driven: suppressedResolvers return empty string for this host.
|
||||
// effectiveSuppressedResolvers() honors --respect-detection: when gbrain
|
||||
// is detected locally, GBRAIN_* resolvers un-suppress so brain-aware
|
||||
// blocks render for users who have gbrain installed.
|
||||
const currentHostConfig = getHostConfig(host);
|
||||
const suppressed = new Set(currentHostConfig.suppressedResolvers || []);
|
||||
const suppressed = effectiveSuppressedResolvers(currentHostConfig);
|
||||
let content = tmplContent.replace(/\{\{(\w+(?::[^}]+)?)\}\}/g, (match, fullKey) => {
|
||||
const parts = fullKey.split(':');
|
||||
const resolverName = parts[0];
|
||||
|
|
|
|||
Loading…
Reference in New Issue