mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-21 04:10:47 +02:00
62 lines
3.0 KiB
TypeScript
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(16);
|
|
}, 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));
|
|
});
|
|
});
|