eklavya 1.45.0 → 1.47.0
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/README.md +11 -1
- package/dist/artifacts.js +17 -0
- package/dist/artifacts.js.map +1 -1
- package/dist/assets/artifact-template.html +3 -0
- package/dist/assets/dashboard.html +476 -30
- package/dist/assets/tutor/SKILL.md +2 -1
- package/dist/assets/tutor/references/writing-mcq.md +11 -1
- package/dist/cli.js +44 -12
- package/dist/cli.js.map +1 -1
- package/dist/dashboard.js +201 -47
- package/dist/dashboard.js.map +1 -1
- package/dist/hooks/checkpoint-quiz.js +3 -2
- package/dist/hooks/checkpoint-quiz.js.map +1 -1
- package/dist/hooks/memory-lib.js +1 -1
- package/dist/hooks/memory-lib.js.map +1 -1
- package/dist/hooks/stop-quiz-check.js +3 -2
- package/dist/hooks/stop-quiz-check.js.map +1 -1
- package/dist/memory/recall.js +1 -1
- package/dist/migrations/019_attempt_corrections.sql +41 -0
- package/dist/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/plugin/agents/explainer.md +11 -6
- package/dist/plugin/skills/tutor/SKILL.md +2 -1
- package/dist/plugin/skills/tutor/references/writing-mcq.md +11 -1
- package/dist/store.js +142 -14
- package/dist/store.js.map +1 -1
- package/dist/telemetry-send.js +9 -7
- package/dist/telemetry-send.js.map +1 -1
- package/dist/tools/get_learner_profile.js +5 -3
- package/dist/tools/get_learner_profile.js.map +1 -1
- package/dist/tools/get_session_quiz_plan.js +1 -1
- package/dist/tools/get_session_quiz_plan.js.map +1 -1
- package/dist/tools/record_attempt.js +48 -8
- package/dist/tools/record_attempt.js.map +1 -1
- package/dist/user-skill/eklavya/SKILL.md +7 -3
- package/dist/user-skill/eklavya-artifacts/SKILL.md +12 -4
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import { loadConfig } from '../config.js';
|
|
|
3
3
|
import { normalizeSlug } from '../slug.js';
|
|
4
4
|
import { decayedScore, isKnown } from '../srs.js';
|
|
5
5
|
import { resolveSessionId } from '../session.js';
|
|
6
|
-
import { conceptBySlug, gradeConcept, hasAskedQuestion, levelStanding, logSessionConcept, promoteIfEarned, syncGate, MAX_MCQ_GRADE, } from '../store.js';
|
|
6
|
+
import { conceptBySlug, gradeConcept, hasAskedQuestion, isMissed, levelStanding, logSessionConcept, promoteIfEarned, syncGate, MAX_MCQ_GRADE, } from '../store.js';
|
|
7
7
|
import { stripAskHeader } from '../ask.js';
|
|
8
8
|
import { CWD_HINT, LIMITS, SESSION_HINT } from './types.js';
|
|
9
9
|
/**
|
|
@@ -11,19 +11,25 @@ import { CWD_HINT, LIMITS, SESSION_HINT } from './types.js';
|
|
|
11
11
|
* contract: the grade and the one-line verdict are already given, the page is
|
|
12
12
|
* written by a background agent, and the session goes back to the work.
|
|
13
13
|
*/
|
|
14
|
-
export function explainInstruction(name, options
|
|
14
|
+
export function explainInstruction(name, options, attemptId, notes) {
|
|
15
15
|
// The tutor relays this in its own words, and a paraphrase kept only the
|
|
16
16
|
// picked and right options. Spelling them out makes the full list the thing
|
|
17
17
|
// it copies.
|
|
18
18
|
const list = options?.length
|
|
19
19
|
? ` Copy all ${options.length} options into its prompt, in this order, not just the picked and right ones: ${options.map((o, i) => `${String.fromCharCode(65 + i)}. ${o}`).join(' | ')}.`
|
|
20
20
|
: '';
|
|
21
|
-
|
|
21
|
+
// The note under each option is what the learner read in the question; the
|
|
22
|
+
// page shows it too, so the two look alike.
|
|
23
|
+
const noteLine = notes?.length ? ' Hand it the one-line note under each option as well, so the page shows each note under its option.' : '';
|
|
24
|
+
// The attempt id links the page to this row, which is what lets the
|
|
25
|
+
// dashboard offer "Correct your answer" on it.
|
|
26
|
+
const link = ` Tell it to pass --attempt ${attemptId} to eklavya artifacts new.`;
|
|
27
|
+
return `Do not wait for this and do not explain further here. Start the eklavya-explainer agent (eklavya:eklavya-explainer when Eklavya is installed as a plugin) in the background, handing it the concept slug, the question, every option offered, the learner's answer and the right answer, so the page can show the question as it was asked.${list}${noteLine}${link} It writes an explainer page on ${name} and opens it. Tell the learner in one line that they missed it, what the right answer is, and that a page on it is on its way, then carry on with the task.`;
|
|
22
28
|
}
|
|
23
29
|
export const recordAttempt = {
|
|
24
30
|
name: 'record_attempt',
|
|
25
31
|
title: 'Record a quiz attempt',
|
|
26
|
-
description: 'Grade one answer on the 0-5 SM-2 scale and persist it. Updates mastery, the next review date, the session gate and this project\'s difficulty level. Record every response, including "I don\'t know" (grade 0, outcome dont_know, after you have taught it) and declines (grade 0, outcome declined). Pass format "mcq" and the options you offered — question takes the stem alone, which is what the repeat check hashes; the options go in options. Multiple choice is capped at grade 4: picking one of four cannot show you know why; omit format only when they typed a real explanation instead of picking. Returns level and level_progress, and level_up on the answer that earns a promotion — say that in one line and move on. Returns explain on a missed answer when explain_on_wrong is on: follow its instruction.',
|
|
32
|
+
description: 'Grade one answer on the 0-5 SM-2 scale and persist it, returning its attempt_id. Updates mastery, the next review date, the session gate and this project\'s difficulty level. Record every response, including "I don\'t know" (grade 0, outcome dont_know, after you have taught it) and declines (grade 0, outcome declined). Pass format "mcq" and the options you offered — question takes the stem alone, which is what the repeat check hashes; the options go in options. With every mcq also pass correct (the right option\'s label, verbatim) and option_notes (the description under each option, same order): they are what lets the learner correct a missed answer after reading its explainer. Multiple choice is capped at grade 4: picking one of four cannot show you know why; omit format only when they typed a real explanation instead of picking. Returns level and level_progress, and level_up on the answer that earns a promotion — say that in one line and move on. Returns explain on a missed answer when explain_on_wrong is on: follow its instruction.',
|
|
27
33
|
inputSchema: {
|
|
28
34
|
session_id: z.string().max(LIMITS.sessionId).optional().describe(SESSION_HINT),
|
|
29
35
|
cwd: z.string().max(LIMITS.cwd).optional().describe(CWD_HINT),
|
|
@@ -54,6 +60,16 @@ export const recordAttempt = {
|
|
|
54
60
|
.max(LIMITS.options)
|
|
55
61
|
.optional()
|
|
56
62
|
.describe('For mcq: the option labels you offered, in the order shown. Not the stem.'),
|
|
63
|
+
correct: z
|
|
64
|
+
.string()
|
|
65
|
+
.max(LIMITS.option)
|
|
66
|
+
.optional()
|
|
67
|
+
.describe('For mcq: the right option\'s label, exactly as it appears in options. Grades a later correction; never shown to the learner by the server.'),
|
|
68
|
+
option_notes: z
|
|
69
|
+
.array(z.string().max(LIMITS.option))
|
|
70
|
+
.max(LIMITS.options)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe('For mcq: the one-line description shown under each option (AskUserQuestion\'s description), in the same order as options.'),
|
|
57
73
|
outcome: z
|
|
58
74
|
.enum(['answered', 'dont_know', 'declined'])
|
|
59
75
|
.optional()
|
|
@@ -92,6 +108,14 @@ export const recordAttempt = {
|
|
|
92
108
|
// reported loudly, because silence here is what let 11 of 16 declines in a
|
|
93
109
|
// real history carry an explanation with nobody noticing.
|
|
94
110
|
const outcomeConflict = args.outcome === 'declined' && typeof args.feedback === 'string' && args.feedback.trim().length > 0;
|
|
111
|
+
// A key that does not line up with the options cannot grade a correction,
|
|
112
|
+
// so it is stored as NULL -- but the answer is real, and losing it would be
|
|
113
|
+
// the worse trade, so the attempt is recorded and the tutor told.
|
|
114
|
+
const options = args.options ?? null;
|
|
115
|
+
const correctOk = args.correct === undefined || (options?.includes(args.correct) ?? false);
|
|
116
|
+
const correct = correctOk ? (args.correct ?? null) : null;
|
|
117
|
+
const notesOk = args.option_notes === undefined || args.option_notes.length === (options?.length ?? 0);
|
|
118
|
+
const optionNotes = notesOk ? (args.option_notes ?? null) : null;
|
|
95
119
|
const capped = args.format === 'mcq' && args.grade > MAX_MCQ_GRADE;
|
|
96
120
|
const grade = capped ? MAX_MCQ_GRADE : args.grade;
|
|
97
121
|
const graded = db.transaction(() => {
|
|
@@ -110,7 +134,9 @@ export const recordAttempt = {
|
|
|
110
134
|
difficulty: args.difficulty,
|
|
111
135
|
feedback: args.feedback ?? null,
|
|
112
136
|
format: args.format ?? null,
|
|
113
|
-
options
|
|
137
|
+
options,
|
|
138
|
+
correct,
|
|
139
|
+
optionNotes,
|
|
114
140
|
// Left NULL rather than guessed when the tutor does not say. An absent
|
|
115
141
|
// answer is a fair hint that nothing was attempted, but it cannot tell
|
|
116
142
|
// "teach me" from "leave it" -- and inventing the difference here would
|
|
@@ -139,21 +165,25 @@ export const recordAttempt = {
|
|
|
139
165
|
// field it was handed far more reliably than a rule it has to remember, and
|
|
140
166
|
// the instruction is composed once, where the config is visible. A decline
|
|
141
167
|
// and a bare skip get nothing -- they asked to move on.
|
|
142
|
-
const missed =
|
|
168
|
+
const missed = isMissed(grade, args.outcome ?? null);
|
|
143
169
|
const explain = config.explain_on_wrong && missed
|
|
144
170
|
? {
|
|
145
171
|
concept: concept.slug,
|
|
146
172
|
name: concept.name,
|
|
147
173
|
question,
|
|
148
|
-
options
|
|
174
|
+
options,
|
|
175
|
+
option_notes: optionNotes,
|
|
149
176
|
answer: args.answer ?? null,
|
|
150
|
-
|
|
177
|
+
correct,
|
|
178
|
+
attempt_id: state.attemptId,
|
|
179
|
+
instruction: explainInstruction(concept.name, options, state.attemptId, optionNotes),
|
|
151
180
|
}
|
|
152
181
|
: null;
|
|
153
182
|
const after = levelStanding(db, config, repoRoot);
|
|
154
183
|
const score = decayedScore(state.score, state.next_review, now);
|
|
155
184
|
return {
|
|
156
185
|
slug: concept.slug,
|
|
186
|
+
attempt_id: state.attemptId,
|
|
157
187
|
recorded_grade: grade,
|
|
158
188
|
// Silence here would let the tutor keep miscalibrating; say what was
|
|
159
189
|
// changed and why.
|
|
@@ -174,6 +204,16 @@ export const recordAttempt = {
|
|
|
174
204
|
// question can be a new one.
|
|
175
205
|
repeat_question: repeatQuestion,
|
|
176
206
|
...(explain ? { explain } : {}),
|
|
207
|
+
...(correctOk
|
|
208
|
+
? {}
|
|
209
|
+
: {
|
|
210
|
+
correct_mismatch: 'correct was not one of the options, so this answer cannot be corrected later. Pass the right option\'s label verbatim, exactly as it appears in options.',
|
|
211
|
+
}),
|
|
212
|
+
...(notesOk
|
|
213
|
+
? {}
|
|
214
|
+
: {
|
|
215
|
+
option_notes_mismatch: 'option_notes needs one note per option, in the same order as options. They were not stored.',
|
|
216
|
+
}),
|
|
177
217
|
...(outcomeConflict
|
|
178
218
|
? {
|
|
179
219
|
outcome_conflict: 'You passed outcome "declined" and also feedback. A decline is dropped without explanation, so if you taught this concept it was a blank: record outcome "dont_know". It matters — a declined concept is never offered again, and in enforced mode that is the only way out of a blocked commit.',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record_attempt.js","sourceRoot":"","sources":["../../src/tools/record_attempt.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EACL,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,QAAQ,EACR,aAAa,GAGd,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAgB,MAAM,YAAY,CAAC;AAE1E;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,
|
|
1
|
+
{"version":3,"file":"record_attempt.js","sourceRoot":"","sources":["../../src/tools/record_attempt.ts"],"names":[],"mappings":"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"}
|
|
@@ -154,7 +154,9 @@ Other keys, same `config set` shape: `pass_threshold`,
|
|
|
154
154
|
"when I get one wrong, make me a page explaining it", or "stop opening pages".
|
|
155
155
|
On, a missed answer also gets an explainer page, written in the background and
|
|
156
156
|
opened, while the session carries on; the page restates the question, its
|
|
157
|
-
options, the pick and the right answer.
|
|
157
|
+
options, the pick and the right answer. When the background dashboard is running, the
|
|
158
|
+
page opens as a dashboard tab; when the right option was recorded, that tab has a **Correct your answer** bar: a right pick
|
|
159
|
+
counts for the concept's score, not for a commit gate or a level. Turning it off is usually wanted per
|
|
158
160
|
project, so default to `--project`. The pages themselves are the
|
|
159
161
|
`eklavya-artifacts` skill's job, not this one's.
|
|
160
162
|
|
|
@@ -284,8 +286,9 @@ eklavya dashboard status # is it running, which version, which database
|
|
|
284
286
|
eklavya dashboard stop # stop the background copy
|
|
285
287
|
```
|
|
286
288
|
|
|
287
|
-
It binds to loopback only and reads the local database; its
|
|
288
|
-
settings change, guarded by a per-start
|
|
289
|
+
It binds to loopback only and reads the local database; its two writes, a
|
|
290
|
+
settings change and a correction of a missed answer, are guarded by a per-start
|
|
291
|
+
token in the page. Worth saying when
|
|
289
292
|
someone asks where their data goes. It keeps running in the background: session
|
|
290
293
|
start starts it when it is down and replaces an older version after an update, so
|
|
291
294
|
the command returns at once with the URL. `dashboard_autostart false` (global
|
|
@@ -317,6 +320,7 @@ project; the ids are the ones `/api/projects` lists.
|
|
|
317
320
|
| what has recall actually saved | `/#/memory/reuse` |
|
|
318
321
|
| is capture healthy | `/#/memory/health` |
|
|
319
322
|
| the pages Eklavya wrote me, search them | `/#/artifacts/dashboard` (or `/explainer` for explainers only) |
|
|
323
|
+
| which explainers can I still correct | `/#/artifacts/dashboard/to-correct`; any page opens as a tab at `/#/artifacts/view/<id>` (the id from `eklavya artifacts list --json`, URL-encoded) |
|
|
320
324
|
| which projects have pages | `/#/artifacts/projects` |
|
|
321
325
|
| change my settings in a page, see what a project overrides | `/#/settings/dashboard`, `/#/settings/user`, `/#/settings/project?project=<path>` |
|
|
322
326
|
|
|
@@ -35,7 +35,10 @@ eklavya artifacts new "<Title>" --description "<one line: what this page answers
|
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
Add `--kind explainer --concept <slug>` when the page explains an Eklavya
|
|
38
|
-
concept, so the dashboard links it to that concept.
|
|
38
|
+
concept, so the dashboard links it to that concept. When the page is for a
|
|
39
|
+
missed question and you were handed its `attempt_id`, also add
|
|
40
|
+
`--attempt <attempt_id>`: when the right option was recorded, the page shows a
|
|
41
|
+
**Correct your answer** bar in the dashboard's viewer.
|
|
39
42
|
|
|
40
43
|
It prints the path of a new file, already carrying the Eklavya template: the
|
|
41
44
|
design tokens inlined, dark by default, the print stylesheet, the PDF and HTML
|
|
@@ -49,7 +52,9 @@ filename.
|
|
|
49
52
|
Edit the file: replace the `<!-- CONTENT … -->` comment with the page, and
|
|
50
53
|
adjust the lede if the description was too short. Leave the `<head>`, the
|
|
51
54
|
`.actions` toolbar and its script, the `.brand` header and the `.made-with`
|
|
52
|
-
footer alone: they carry the Eklavya favicon, share tags and link home.
|
|
55
|
+
footer alone: they carry the Eklavya favicon, share tags and link home. Add no
|
|
56
|
+
script for the dashboard's viewer (height reports, scrolling, theme messages):
|
|
57
|
+
the dashboard adds its own to every page it frames.
|
|
53
58
|
|
|
54
59
|
**Write for the person reading it.** Plain English first: what the thing *does*
|
|
55
60
|
before what it is called. One idea per section under an `<h2>`. A concrete
|
|
@@ -80,7 +85,8 @@ Artifacts gallery, so put the one that explains the page first.
|
|
|
80
85
|
**Stay on the design system.** Components already in the template: `.eyebrow`,
|
|
81
86
|
`.lede`, `.card`, `.grid`, `.chip` (`.warn`, `.bad`), `.stat` (`.k`, `.v`,
|
|
82
87
|
`.d`), `.callout`, `td.num`, and `ol.options` with `li.picked` / `li.right`
|
|
83
|
-
for restating a missed question
|
|
88
|
+
for restating a missed question; put the one-line note shown under an option
|
|
89
|
+
in the question in `<span class="note">…</span>` inside its `<li>`. Code goes in `<pre><code>`, escaped, with
|
|
84
90
|
`data-lang="css"` (or `ts`, `sql`, …) on the `<pre>` for its label; the template
|
|
85
91
|
colours comments, keywords, strings and numbers itself, so never hand-colour it.
|
|
86
92
|
Reuse these before adding CSS. Any CSS you add
|
|
@@ -123,7 +129,9 @@ figures); never on a tall wrapper, or the PDF gets half-empty pages. No
|
|
|
123
129
|
eklavya artifacts open "<the path new printed>"
|
|
124
130
|
```
|
|
125
131
|
|
|
126
|
-
|
|
132
|
+
It prints what it opened: the page's address in the dashboard's viewer, where
|
|
133
|
+
it opens as a tab (when the background dashboard is on), or else the file. Report
|
|
134
|
+
the path in one line. Do not mention links, publishing or sharing.
|
|
127
135
|
|
|
128
136
|
`eklavya artifacts list` shows every page, newest first (`--here` for this
|
|
129
137
|
project, `--json` for the ids); `eklavya dashboard` then **Artifacts** is the
|
package/package.json
CHANGED