Files
gstack/test/gstack2-skills.test.ts
T
2026-07-21 19:19:23 -07:00

62 lines
3.0 KiB
TypeScript

import { describe, expect, test } from 'bun:test';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { blobShaForPath, pinnedRevisionPath } from '../scripts/gstack2/render-legacy';
import { runParity } from '../scripts/gstack2/run-parity';
const ROOT = join(import.meta.dir, '..');
describe('GStack 2 skill parity', () => {
test('normalizes Windows-style repository paths for pinned Git lookups', () => {
const windowsPath = String.raw`cso\SKILL.md.tmpl`;
expect(pinnedRevisionPath(windowsPath))
.toBe(pinnedRevisionPath('cso/SKILL.md.tmpl'));
expect(blobShaForPath(windowsPath))
.toBe(blobShaForPath('cso/SKILL.md.tmpl'));
});
test('pins hash-provenance asset sources to LF on every checkout', () => {
const attributes = readFileSync(join(ROOT, '.gitattributes'), 'utf8');
const normalizedLines = attributes.split(/\r?\n/).map((line) => line.trim().replace(/\s+/g, ' '));
for (const pattern of ['*.swift', '*.h', '*.m', '*.template']) {
expect(normalizedLines).toContain(`${pattern} text eol=lf`);
}
});
test('preserves the pinned specialist corpus and generated evidence', () => {
const result = runParity();
expect(result.sources).toBe(55);
expect(result.sections).toBe(16);
expect(result.regressions).toBe(22);
}, 30_000);
test('keeps image generation host-native, optional, and provider-free', () => {
const design = readFileSync(join(ROOT, 'skills', 'design', 'SKILL.md'), 'utf8');
expect(design).toContain('Use host-native image generation');
expect(design).toContain('keep it optional');
expect(design).toContain('Never install an image provider, local model, weights, GPU runtime, or background image server');
});
test('does not overclaim safety-hook enforcement in portable installs', () => {
const debug = readFileSync(join(ROOT, 'skills', 'debug', 'SKILL.md'), 'utf8');
expect(debug).toContain('inline advisory policy unless the active host explicitly confirms an installed hook');
expect(debug).toContain('never claim every command is intercepted when no hook is active');
});
test('keeps the default catalog at least 75 percent below the measured 1.x baseline', () => {
const baselineTokenEquivalents = 1_100;
const catalogCharacters = ['plan', 'design', 'qa', 'debug', 'review', 'ship']
.map((skill) => readFileSync(join(ROOT, 'skills', skill, 'SKILL.md'), 'utf8'))
.reduce((total, body) => {
const name = body.match(/^name:\s*(.+)$/m)?.[1]?.trim() ?? '';
const descriptionBlock = body.match(/^description:\s*>-\r?\n((?: .*\r?\n)+)/m)?.[1] ?? '';
const description = descriptionBlock.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).join(' ');
expect(name).not.toBe('');
expect(description).not.toBe('');
return total + name.length + description.length;
}, 0);
const estimatedTokens = Math.ceil(catalogCharacters / 4);
expect(estimatedTokens).toBeLessThanOrEqual(Math.floor(baselineTokenEquivalents * 0.25));
});
});