feat: productionize learning engine and classroom

This commit is contained in:
inman
2026-08-16 21:44:52 +08:00
parent 2d04197f3f
commit ba35adfbfa
124 changed files with 9071 additions and 796 deletions

View File

@@ -0,0 +1,78 @@
import { describe, expect, it } from 'vitest';
import {
validateCourseAgentAnchor,
validateCoursePackageDescriptor,
} from '../src/index.js';
const SHA = 'a'.repeat(64);
describe('course package descriptor', () => {
it('accepts immutable unique-course metadata without a product version', () => {
const descriptor = {
schemaVersion: 1,
kind: 'makelore-course-package',
courseId: 'course_python_basics',
contentHash: SHA,
archiveSha256: 'b'.repeat(64),
archiveBytes: 1024,
formatVersion: 1,
minPlayerVersion: '0.1.0',
title: 'Python 零基础入门',
sceneCount: 10,
capabilities: {
sceneKinds: ['slide', 'interactive', 'quiz'],
hasAudio: false,
hasWhiteboard: false,
hasAgent: true,
},
createdAt: '2026-08-16T00:00:00.000Z',
};
expect(validateCoursePackageDescriptor(descriptor)).toEqual({
ok: true,
value: descriptor,
errors: [],
});
expect(descriptor).not.toHaveProperty('version');
});
it('rejects malformed hashes and zero-byte archives', () => {
const result = validateCoursePackageDescriptor({
schemaVersion: 1,
kind: 'makelore-course-package',
courseId: 'course_1',
contentHash: 'bad',
archiveSha256: SHA,
archiveBytes: 0,
formatVersion: 1,
minPlayerVersion: '0.1.0',
title: 'Course',
sceneCount: 1,
capabilities: {
sceneKinds: ['slide'],
hasAudio: false,
hasWhiteboard: false,
hasAgent: false,
},
createdAt: '2026-08-16T00:00:00.000Z',
});
expect(result.ok).toBe(false);
expect(result.errors).toContain('contentHash must be a SHA-256 hex string');
expect(result.errors).toContain('archiveBytes must be a positive integer');
});
});
describe('agent anchor', () => {
it('binds an Agent request to an exact course and playback position', () => {
expect(
validateCourseAgentAnchor({
courseId: 'course_python_basics',
contentHash: SHA,
sceneOrder: 2,
actionIndex: 1,
positionMs: 3200,
}).ok,
).toBe(true);
});
});