v1.93.12.0 fix(loadouts): lite install keeps gbrain detection and disabled_skills; pin the evidence rule (GST-944) (#3874)

* fix(loadouts): lite install keeps gbrain detection and disabled_skills; pin the Claims Need Evidence rule (GST-944)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* fix(loadouts): one gbrain detection read serves identity and render; normalize disabled_skills like gstack-config; isolate install tests from ~/.gstack (GST-944 review)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* test(loadouts): set the empty state root in beforeAll (GST-944)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-11-02 18:05:23 +00:00
1 parent 24a47db3d9
commit 8f08cb76ac
10 files changed
+75 -17

No files matched your search

+4 -2
View File
@@ -55,6 +55,8 @@ export interface GenerationOptions {
catalogMode?: 'trim' | 'full';
explainLevel?: 'default' | 'terse';
respectDetection?: boolean;
/** A detection result the caller already read; wins over respectDetection so one read serves identity and render. */
gbrainDetected?: boolean;
log?: (message: string) => void;
planMode?: boolean;
/** Module loadout (scripts/modules.ts selectModules); null/undefined = `full`. */
@@ -94,7 +96,7 @@ export interface GenerationResult {
}
/** Canonical generation never reads local detection state unless opted in. */
function loadGbrainOverride(respectDetection: boolean): boolean {
export function loadGbrainOverride(respectDetection: boolean): boolean {
if (!respectDetection) return false;
const stateDir = resolveStateRoot();
try {
@@ -989,7 +991,7 @@ export async function runGeneration(settings: GenerationOptions = {}): Promise<G
model: settings.model ?? null,
catalogMode: settings.catalogMode ?? 'trim',
explainLevel: settings.explainLevel ?? 'default',
gbrainDetected: loadGbrainOverride(settings.respectDetection ?? false),
gbrainDetected: settings.gbrainDetected ?? loadGbrainOverride(settings.respectDetection ?? false),
planMode: settings.planMode ?? true,
modules: settings.modules ?? null,
};
+9 -2
View File
@@ -26,7 +26,8 @@ import { createHash, randomBytes } from 'node:crypto';
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { runGeneration } from './gen-skill-docs';
import { readConfigKey } from '../lib/state-root';
import { loadGbrainOverride, runGeneration } from './gen-skill-docs';
import { resolveModel } from './models';
import { ModuleError, type ModuleSelection } from './modules';
import { LOCK_FILE, danglingReferences } from './modules-render';
@@ -148,6 +149,10 @@ export async function installLoadout(request: InstallRequest): Promise<InstallRe
const planMode = request.planMode ?? true;
const model = request.boundModel ? resolveModel(request.boundModel) : null;
const selection: ModuleSelection = { ...request.selection, boundModel: request.boundModel ?? undefined, fullRoot: request.boundModel ? request.fullRoot : undefined };
const gbrainDetected = loadGbrainOverride(true);
const disabledSkills = [...new Set((readConfigKey('disabled_skills') ?? '').replace(/["']/g, '').split(/[\s,]+/)
.map(n => n.replace(/^\//, '')).filter(n => n !== 'gstack' && n !== 'gstack-upgrade')
.map(n => n.replace(/^gstack-/, '')).filter(n => /^[a-z0-9-]+$/.test(n)))].sort();
const identity = {
loadout: selection.name,
excluded: [...selection.excluded].sort(),
@@ -157,6 +162,8 @@ export async function installLoadout(request: InstallRequest): Promise<InstallRe
host,
overlay_model: model,
plan_mode: planMode,
gbrain_detected: gbrainDetected,
disabled_skills: disabledSkills,
source_tree: sourceTree(source),
};
const identitySha = sha256(JSON.stringify(identity));
@@ -174,7 +181,7 @@ export async function installLoadout(request: InstallRequest): Promise<InstallRe
}
const stage = `${final}.stage-${process.pid}-${randomBytes(4).toString('hex')}`;
try {
const result = await runGeneration({ host, outputRoot: stage, contentLinkRoot: final, installRoot: request.fullRoot && request.fullRoot !== path.join(os.homedir(), '.claude/skills') ? path.join(request.fullRoot, 'gstack') : null, model, planMode, modules: selection });
const result = await runGeneration({ host, outputRoot: stage, contentLinkRoot: final, installRoot: request.fullRoot && request.fullRoot !== path.join(os.homedir(), '.claude/skills') ? path.join(request.fullRoot, 'gstack') : null, model, planMode, modules: selection, gbrainDetected, disabledSkills });
const errors = result.diagnostics.filter(d => d.kind === 'error').map(d => d.message);
if (result.exitCode !== 0 || errors.length) {
throw new ModuleError('RENDER_FAILED', `gen-skill-docs failed: ${errors.join('; ') || 'exit 1'}`, 'fix the named template or module, then rerun; side effects: none, safe to retry');