@lssm/example.learning-patterns 0.0.0-canary-20251213172311 → 0.0.0-canary-20251215231151
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +14 -4
- package/CHANGELOG.md +2 -2
- package/README.md +1 -0
- package/dist/libs/contracts/src/docs/index.js +1 -1
- package/dist/libs/contracts/src/docs/tech/auth/better-auth-nextjs.docblock.js +58 -0
- package/dist/libs/contracts/src/docs/tech/studio/learning-events.docblock.js +1 -0
- package/dist/libs/contracts/src/docs/tech/studio/learning-journeys.docblock.js +57 -0
- package/dist/libs/contracts/src/docs/tech/studio/platform-admin-panel.docblock.js +63 -0
- package/dist/libs/contracts/src/docs/tech/studio/project-access-teams.docblock.js +36 -0
- package/dist/libs/contracts/src/docs/tech/studio/project-routing.docblock.js +1 -0
- package/dist/libs/contracts/src/docs/tech/studio/sandbox-unlogged.docblock.js +20 -0
- package/dist/libs/contracts/src/docs/tech/studio/team-invitations.docblock.js +65 -0
- package/dist/libs/contracts/src/docs/tech/studio/workspace-ops.docblock.js +1 -0
- package/dist/libs/contracts/src/docs/tech/studio/workspaces.docblock.js +41 -0
- package/package.json +2 -2
- package/src/docs/index.ts +0 -2
- package/src/docs/learning-patterns.docblock.ts +4 -4
- package/src/events.ts +2 -3
- package/src/example.ts +2 -3
- package/src/index.ts +0 -2
- package/src/learning-patterns.test.ts +51 -16
- package/src/tracks/ambient-coach.ts +3 -3
- package/src/tracks/drills.ts +4 -3
- package/src/tracks/index.ts +0 -2
- package/src/tracks/quests.ts +8 -4
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/tsdown.config.js +1 -0
|
@@ -46,7 +46,8 @@ const getAvailability = (
|
|
|
46
46
|
const baseTime = startedAt.getTime();
|
|
47
47
|
let unlockTime = baseTime;
|
|
48
48
|
if (availability.unlockOnDay !== undefined) {
|
|
49
|
-
unlockTime =
|
|
49
|
+
unlockTime =
|
|
50
|
+
baseTime + (availability.unlockOnDay - 1) * 24 * 60 * 60 * 1000;
|
|
50
51
|
}
|
|
51
52
|
if (availability.unlockAfterHours !== undefined) {
|
|
52
53
|
unlockTime = baseTime + availability.unlockAfterHours * 60 * 60 * 1000;
|
|
@@ -54,7 +55,9 @@ const getAvailability = (
|
|
|
54
55
|
const availableAt = new Date(unlockTime);
|
|
55
56
|
const dueAt =
|
|
56
57
|
availability.dueWithinHours !== undefined
|
|
57
|
-
? new Date(
|
|
58
|
+
? new Date(
|
|
59
|
+
availableAt.getTime() + availability.dueWithinHours * 60 * 60 * 1000
|
|
60
|
+
)
|
|
58
61
|
: undefined;
|
|
59
62
|
return { availableAt, dueAt };
|
|
60
63
|
};
|
|
@@ -66,18 +69,21 @@ const matchesCondition = (
|
|
|
66
69
|
): { matched: boolean; occurrences?: number; masteryCount?: number } => {
|
|
67
70
|
if ((condition.kind ?? 'event') === 'event') {
|
|
68
71
|
if (condition.eventName !== event.name) return { matched: false };
|
|
69
|
-
if (!matchesFilter(condition.payloadFilter, event.payload))
|
|
72
|
+
if (!matchesFilter(condition.payloadFilter, event.payload))
|
|
73
|
+
return { matched: false };
|
|
70
74
|
return { matched: true };
|
|
71
75
|
}
|
|
72
76
|
if (condition.kind === 'count') {
|
|
73
77
|
if (condition.eventName !== event.name) return { matched: false };
|
|
74
|
-
if (!matchesFilter(condition.payloadFilter, event.payload))
|
|
78
|
+
if (!matchesFilter(condition.payloadFilter, event.payload))
|
|
79
|
+
return { matched: false };
|
|
75
80
|
const occurrences = step.occurrences + 1;
|
|
76
81
|
return { matched: occurrences >= condition.atLeast, occurrences };
|
|
77
82
|
}
|
|
78
83
|
if (condition.kind === 'srs_mastery') {
|
|
79
84
|
if (condition.eventName !== event.name) return { matched: false };
|
|
80
|
-
if (!matchesFilter(condition.payloadFilter, event.payload))
|
|
85
|
+
if (!matchesFilter(condition.payloadFilter, event.payload))
|
|
86
|
+
return { matched: false };
|
|
81
87
|
const masteryKey = condition.masteryField ?? 'mastery';
|
|
82
88
|
const masteryValue = event.payload?.[masteryKey];
|
|
83
89
|
if (typeof masteryValue !== 'number') return { matched: false };
|
|
@@ -103,7 +109,10 @@ function initProgress(track: LearningJourneyTrackSpec): StepState[] {
|
|
|
103
109
|
}));
|
|
104
110
|
}
|
|
105
111
|
|
|
106
|
-
function applyEvents(
|
|
112
|
+
function applyEvents(
|
|
113
|
+
track: LearningJourneyTrackSpec,
|
|
114
|
+
events: LearningEvent[]
|
|
115
|
+
): StepState[] {
|
|
107
116
|
const steps = initProgress(track);
|
|
108
117
|
let startedAt: Date | undefined;
|
|
109
118
|
for (const event of events) {
|
|
@@ -114,7 +123,10 @@ function applyEvents(track: LearningJourneyTrackSpec, events: LearningEvent[]):
|
|
|
114
123
|
const state = steps[index];
|
|
115
124
|
if (!spec || !state) continue;
|
|
116
125
|
if (state.status === 'COMPLETED') continue;
|
|
117
|
-
const { availableAt, dueAt } = getAvailability(
|
|
126
|
+
const { availableAt, dueAt } = getAvailability(
|
|
127
|
+
spec.availability,
|
|
128
|
+
startedAt
|
|
129
|
+
);
|
|
118
130
|
state.availableAt = availableAt;
|
|
119
131
|
state.dueAt = dueAt;
|
|
120
132
|
if (availableAt && eventTime < availableAt) continue;
|
|
@@ -132,9 +144,18 @@ describe('@lssm/example.learning-patterns tracks', () => {
|
|
|
132
144
|
it('drills track progresses via session count + mastery', () => {
|
|
133
145
|
const events: LearningEvent[] = [
|
|
134
146
|
{ name: LEARNING_EVENTS.DRILL_SESSION_COMPLETED },
|
|
135
|
-
{
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
{
|
|
148
|
+
name: LEARNING_EVENTS.DRILL_SESSION_COMPLETED,
|
|
149
|
+
payload: { accuracyBucket: 'high' },
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
name: LEARNING_EVENTS.DRILL_SESSION_COMPLETED,
|
|
153
|
+
payload: { accuracyBucket: 'high' },
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: LEARNING_EVENTS.DRILL_SESSION_COMPLETED,
|
|
157
|
+
payload: { accuracyBucket: 'high' },
|
|
158
|
+
},
|
|
138
159
|
...Array.from({ length: 5 }).map(() => ({
|
|
139
160
|
name: LEARNING_EVENTS.DRILL_CARD_MASTERED,
|
|
140
161
|
payload: { skillId: 's1', mastery: 0.9 },
|
|
@@ -179,8 +200,18 @@ describe('@lssm/example.learning-patterns tracks', () => {
|
|
|
179
200
|
describe('@lssm/example.learning-patterns XP + streak + SRS determinism', () => {
|
|
180
201
|
it('XP engine produces deterministic results for streak bonus inputs', () => {
|
|
181
202
|
const xp = new XPEngine();
|
|
182
|
-
const r1 = xp.calculate({
|
|
183
|
-
|
|
203
|
+
const r1 = xp.calculate({
|
|
204
|
+
activity: 'lesson_complete',
|
|
205
|
+
score: 90,
|
|
206
|
+
attemptNumber: 1,
|
|
207
|
+
currentStreak: 7,
|
|
208
|
+
});
|
|
209
|
+
const r2 = xp.calculate({
|
|
210
|
+
activity: 'lesson_complete',
|
|
211
|
+
score: 90,
|
|
212
|
+
attemptNumber: 1,
|
|
213
|
+
currentStreak: 7,
|
|
214
|
+
});
|
|
184
215
|
expect(r1.totalXp).toBe(r2.totalXp);
|
|
185
216
|
expect(r1.totalXp).toBeGreaterThan(0);
|
|
186
217
|
});
|
|
@@ -195,8 +226,14 @@ describe('@lssm/example.learning-patterns XP + streak + SRS determinism', () =>
|
|
|
195
226
|
freezesRemaining: 0,
|
|
196
227
|
freezeUsedAt: null,
|
|
197
228
|
};
|
|
198
|
-
const day1 = streak.update(
|
|
199
|
-
|
|
229
|
+
const day1 = streak.update(
|
|
230
|
+
initial,
|
|
231
|
+
new Date('2026-01-01T10:00:00.000Z')
|
|
232
|
+
).state;
|
|
233
|
+
const day2 = streak.update(
|
|
234
|
+
day1,
|
|
235
|
+
new Date('2026-01-02T10:00:00.000Z')
|
|
236
|
+
).state;
|
|
200
237
|
expect(day2.currentStreak).toBe(2);
|
|
201
238
|
});
|
|
202
239
|
|
|
@@ -217,5 +254,3 @@ describe('@lssm/example.learning-patterns XP + streak + SRS determinism', () =>
|
|
|
217
254
|
expect(result.nextReviewAt.toISOString()).toBe('2026-01-01T00:10:00.000Z');
|
|
218
255
|
});
|
|
219
256
|
});
|
|
220
|
-
|
|
221
|
-
|
|
@@ -39,6 +39,6 @@ export const ambientCoachTrack: LearningJourneyTrackSpec = {
|
|
|
39
39
|
],
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
export const ambientCoachTracks: LearningJourneyTrackSpec[] = [
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
export const ambientCoachTracks: LearningJourneyTrackSpec[] = [
|
|
43
|
+
ambientCoachTrack,
|
|
44
|
+
];
|
package/src/tracks/drills.ts
CHANGED
|
@@ -13,7 +13,10 @@ export const drillsTrack: LearningJourneyTrackSpec = {
|
|
|
13
13
|
id: 'complete_first_session',
|
|
14
14
|
title: 'Complete your first session',
|
|
15
15
|
order: 1,
|
|
16
|
-
completion: {
|
|
16
|
+
completion: {
|
|
17
|
+
kind: 'event',
|
|
18
|
+
eventName: LEARNING_EVENTS.DRILL_SESSION_COMPLETED,
|
|
19
|
+
},
|
|
17
20
|
xpReward: 10,
|
|
18
21
|
},
|
|
19
22
|
{
|
|
@@ -46,5 +49,3 @@ export const drillsTrack: LearningJourneyTrackSpec = {
|
|
|
46
49
|
};
|
|
47
50
|
|
|
48
51
|
export const drillTracks: LearningJourneyTrackSpec[] = [drillsTrack];
|
|
49
|
-
|
|
50
|
-
|
package/src/tracks/index.ts
CHANGED
package/src/tracks/quests.ts
CHANGED
|
@@ -20,7 +20,10 @@ export const questTrack: LearningJourneyTrackSpec = {
|
|
|
20
20
|
id: 'day1_complete',
|
|
21
21
|
title: 'Complete day 1 step',
|
|
22
22
|
order: 2,
|
|
23
|
-
completion: {
|
|
23
|
+
completion: {
|
|
24
|
+
kind: 'event',
|
|
25
|
+
eventName: LEARNING_EVENTS.QUEST_STEP_COMPLETED,
|
|
26
|
+
},
|
|
24
27
|
availability: { unlockOnDay: 1, dueWithinHours: 48 },
|
|
25
28
|
xpReward: 10,
|
|
26
29
|
},
|
|
@@ -28,7 +31,10 @@ export const questTrack: LearningJourneyTrackSpec = {
|
|
|
28
31
|
id: 'day2_complete',
|
|
29
32
|
title: 'Complete day 2 step',
|
|
30
33
|
order: 3,
|
|
31
|
-
completion: {
|
|
34
|
+
completion: {
|
|
35
|
+
kind: 'event',
|
|
36
|
+
eventName: LEARNING_EVENTS.QUEST_STEP_COMPLETED,
|
|
37
|
+
},
|
|
32
38
|
availability: { unlockOnDay: 2, dueWithinHours: 48 },
|
|
33
39
|
xpReward: 10,
|
|
34
40
|
},
|
|
@@ -36,5 +42,3 @@ export const questTrack: LearningJourneyTrackSpec = {
|
|
|
36
42
|
};
|
|
37
43
|
|
|
38
44
|
export const questTracks: LearningJourneyTrackSpec[] = [questTrack];
|
|
39
|
-
|
|
40
|
-
|
package/tsconfig.json
CHANGED