eklavya-mcp 1.0.0 → 1.0.1
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/bin/eklavya-mcp.sh +1 -1
- package/dist/assets/tutor-skill.md +34 -3
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -1
- package/dist/server.js +14 -1
- package/dist/server.js.map +1 -1
- package/dist/store.js +47 -1
- package/dist/store.js.map +1 -1
- package/dist/tools/config_tools.js +2 -0
- package/dist/tools/config_tools.js.map +1 -1
- package/dist/tools/get_learner_profile.js +11 -2
- package/dist/tools/get_learner_profile.js.map +1 -1
- package/dist/tools/get_session_quiz_plan.js +122 -29
- package/dist/tools/get_session_quiz_plan.js.map +1 -1
- package/dist/tools/record_attempt.js +6 -1
- package/dist/tools/record_attempt.js.map +1 -1
- package/package.json +1 -1
package/bin/eklavya-mcp.sh
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
# Keep PINNED_VERSION in step with .claude-plugin/plugin.json and
|
|
13
13
|
# mcp/package.json. A test asserts all three match.
|
|
14
14
|
|
|
15
|
-
PINNED_VERSION="1.0.
|
|
15
|
+
PINNED_VERSION="1.0.1"
|
|
16
16
|
|
|
17
17
|
MCP_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
|
18
18
|
LOCAL_SERVER="$MCP_DIR/dist/server.js"
|
|
@@ -47,9 +47,40 @@ Call `get_learner_profile` first. Always. It tells you:
|
|
|
47
47
|
- `due_for_review` — what spaced repetition says is ready to resurface
|
|
48
48
|
- `suggested_tier` — roughly where to pitch
|
|
49
49
|
|
|
50
|
-
Then call `get_session_quiz_plan`. It returns the concepts worth asking about *and the tier to ask each one at
|
|
50
|
+
Then call `get_session_quiz_plan`. It returns the concepts worth asking about *and the tier to ask each one at*, plus everything you need to write a question that has not been asked before:
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
| Field | What it is for |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `tier_to_ask` | The difficulty to pitch at. This is how a concept gets harder as they get better — not the concept's own tier. |
|
|
55
|
+
| `description` | The canonical one-line meaning of the concept. Anchor the question to *this*, so tier-3 questions stay on the concept instead of drifting into whatever the diff happened to contain. |
|
|
56
|
+
| `context` | The real decision in the real file. This is what makes the question grounded. |
|
|
57
|
+
| `asked_before` | Questions this developer has **already been asked** about this concept, with the tier and grade each got. |
|
|
58
|
+
| `prereqs_unmet` | Prerequisites they have not mastered yet. |
|
|
59
|
+
| `last_grade` | How the last attempt went. |
|
|
60
|
+
|
|
61
|
+
If `questions_needed` is 0, say nothing and move on. `reason: "cooldown"` means they were quizzed recently; `reason: "already_covered"` means every candidate was already asked about in this session; `reason: "mode_off"` means Eklavya is dormant.
|
|
62
|
+
|
|
63
|
+
When the developer explicitly asked to be quizzed, pass `ignore_cooldown: true` — the cadence limit exists to stop you nagging, not to refuse a request. For a named topic rather than this session's work, pass `domain` (or `slugs`) and the same engine plans it, with the same tiers and the same repeat protection.
|
|
64
|
+
|
|
65
|
+
## Never the same question twice
|
|
66
|
+
|
|
67
|
+
This is the promise the whole tool rests on, and `asked_before` is how you keep it.
|
|
68
|
+
|
|
69
|
+
- **A question in `asked_before` is spent.** Not "reword it" — spent. Ask a different thing about the same concept.
|
|
70
|
+
- If they scored 4 or 5 on it, `tier_to_ask` has already moved up: the new question should be asking for something the old one did not (mechanism → judgement → failure mode).
|
|
71
|
+
- If they scored 1 or 2 on it, come at the *same* level from a different angle. Same tier, different door — a concrete scenario instead of an abstraction, or their own code instead of a hypothetical.
|
|
72
|
+
- If `asked_before` is empty, you have a clean slate; use `tier_to_ask` and `description`.
|
|
73
|
+
- `record_attempt` returns `repeat_question: true` if you asked something already on record. Treat it as a mistake you just made, and do not do it again in the same quiz.
|
|
74
|
+
|
|
75
|
+
The `known` list in the profile is the other half: **never ask about a slug in `known`** unless it also appears in `due_for_review`. Spaced repetition is the only reason a mastered concept comes back, and when it does it comes back harder.
|
|
76
|
+
|
|
77
|
+
## Unmet prerequisites
|
|
78
|
+
|
|
79
|
+
`prereqs_unmet` is a warning that a question would be unfair, not hard. If a concept has unmet prerequisites:
|
|
80
|
+
|
|
81
|
+
- Ask about the prerequisite instead, if it is in the plan — the plan already orders foundations first.
|
|
82
|
+
- Otherwise drop the question a tier and make it mechanism-level. "Why this rather than the alternative" is not answerable by someone who does not yet have the alternative.
|
|
83
|
+
- Say the dependency out loud in your feedback. Knowing *what to learn next* is half of what the graph is for.
|
|
53
84
|
|
|
54
85
|
## Asking
|
|
55
86
|
|
|
@@ -74,7 +105,7 @@ Definitions are tier 1 **only**. If you find yourself asking "what is X" at tier
|
|
|
74
105
|
|
|
75
106
|
## Grading
|
|
76
107
|
|
|
77
|
-
Call `record_attempt` for **every** answer, including skips. Grade honestly on SM-2's 0–5:
|
|
108
|
+
Call `record_attempt` for **every** answer, including skips — pass `question` verbatim, because that text is what stops the same question coming back later. Grade honestly on SM-2's 0–5:
|
|
78
109
|
|
|
79
110
|
| Grade | Means |
|
|
80
111
|
|---|---|
|
package/dist/cli.js
CHANGED
|
@@ -21,7 +21,8 @@ Usage:
|
|
|
21
21
|
eklavya db-path Print the database location
|
|
22
22
|
|
|
23
23
|
Config keys: mode, pass_threshold, max_questions_per_task,
|
|
24
|
-
min_minutes_between_quizzes, max_new_concepts_per_session,
|
|
24
|
+
min_minutes_between_quizzes, max_new_concepts_per_session,
|
|
25
|
+
max_stop_blocks_per_session, quiet
|
|
25
26
|
`;
|
|
26
27
|
function fail(message) {
|
|
27
28
|
process.stderr.write(`${message}\n`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5F,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,MAAM,KAAK,GAAG
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5F,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,MAAM,KAAK,GAAG;;;;;;;;;;;;CAYb,CAAC;AAEF,SAAS,IAAI,CAAC,OAAe;IAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,WAAW,CAAC,IAAc;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IACnE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,IAAI,CAAC,gFAAgF,CAAC,CAAC;IACzF,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAEtF,MAAM,KAAK,GAAG;;;;;;;;;;;EAWd,KAAK,CAAC,IAAI,EAAE;CACb,CAAC;IAEA,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,GAAG;YAAE,IAAI,CAAC,0BAA0B,CAAC,CAAC;QAC3C,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,aAAa,CAAC,IAAc;IACnC,MAAM,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAE9B,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACtE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,QAAQ,CAAC,UAAU,IAAI,CAAC,CAAC;QAC3D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,QAAQ,CAAC,QAAQ,IAAI,QAAQ,IAAI,CAAC,CAAC;QACnE,OAAO;IACT,CAAC;IAED,IAAI,MAAM,KAAK,KAAK;QAAE,IAAI,CAAC,0BAA0B,MAAM,IAAI,CAAC,CAAC;IACjE,IAAI,CAAC,GAAG,IAAI,KAAK,KAAK,SAAS;QAAE,IAAI,CAAC,yCAAyC,CAAC,CAAC;IACjF,IAAI,CAAC,CAAC,GAAG,IAAI,cAAc,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,oBAAoB,GAAG,aAAa,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,IAAI,MAAM,GAAY,KAAK,CAAC;IAC5B,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO;QAAE,MAAM,GAAG,KAAK,KAAK,MAAM,CAAC;SAChE,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAAE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9E,IAAI,MAAc,CAAC;IACnB,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,CAAC,QAAQ,CAAC,QAAQ;YAAE,IAAI,CAAC,0EAA0E,CAAC,CAAC;QACzG,MAAM,GAAG,QAAQ,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;IAC/E,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC;IAC/B,CAAC;IAED,eAAe,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,MAAM,IAAI,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,MAAM;IACb,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;IACtB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,EAAE,GAAG,IAAI,CAAC;IAEd,KAAK,CAAC,IAAI,CAAC,aAAa,WAAW,EAAE,EAAE,CAAC,CAAC;IACzC,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,sBAAsB,EAAE,CAAC,CAAC;IAEpF,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;QACxB,MAAM,QAAQ,GAAI,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,EAAoB,CAAC,CAAC,CAAC;QAC1F,MAAM,QAAQ,GAAI,EAAE,CAAC,OAAO,CAAC,iCAAiC,CAAC,CAAC,GAAG,EAAoB,CAAC,CAAC,CAAC;QAC1F,MAAM,KAAK,GACT,EAAE,CAAC,OAAO,CAAC,iEAAiE,CAAC,CAAC,GAAG,EAClF,CAAC,CAAC,CAAC;QACJ,KAAK,CAAC,IAAI,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;QACpC,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAC/E,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,EAAE,GAAG,KAAK,CAAC;QACX,KAAK,CAAC,IAAI,CAAC,mBAAmB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAC9B,KAAK,CAAC,IAAI,CAAC,aAAa,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAE/F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,EAAE;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,IAAI;IACX,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEjD,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,cAAc;YACjB,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC3B,KAAK,QAAQ;YACX,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;QAC7B,KAAK,QAAQ;YACX,OAAO,MAAM,EAAE,CAAC;QAClB,KAAK,SAAS;YACZ,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,CAAC;YACtC,OAAO;QACT,KAAK,SAAS,CAAC;QACf,KAAK,IAAI,CAAC;QACV,KAAK,QAAQ;YACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5B,OAAO;QACT;YACE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -10,6 +10,7 @@ export const DEFAULT_CONFIG = {
|
|
|
10
10
|
domains_enabled: ['*'],
|
|
11
11
|
quiet: false,
|
|
12
12
|
max_new_concepts_per_session: 8,
|
|
13
|
+
max_stop_blocks_per_session: 3,
|
|
13
14
|
};
|
|
14
15
|
export const REPO_CONFIG_FILE = '.eklavya.json';
|
|
15
16
|
function realPath(p) {
|
|
@@ -83,6 +84,10 @@ function coerce(raw, base) {
|
|
|
83
84
|
raw.max_new_concepts_per_session >= 0) {
|
|
84
85
|
out.max_new_concepts_per_session = Math.floor(raw.max_new_concepts_per_session);
|
|
85
86
|
}
|
|
87
|
+
if (typeof raw.max_stop_blocks_per_session === 'number' &&
|
|
88
|
+
raw.max_stop_blocks_per_session >= 0) {
|
|
89
|
+
out.max_stop_blocks_per_session = Math.floor(raw.max_stop_blocks_per_session);
|
|
90
|
+
}
|
|
86
91
|
return out;
|
|
87
92
|
}
|
|
88
93
|
/** Global config merged with the repo's, repo winning (PRD §11). */
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
2
3
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
4
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
5
|
import { openDb } from './db.js';
|
|
5
6
|
import { dbPath } from './paths.js';
|
|
6
7
|
import { registerTools } from './tools/index.js';
|
|
8
|
+
// Read the version rather than hardcoding it: a literal here silently reports a
|
|
9
|
+
// stale version forever, since nothing about publishing touches this file.
|
|
10
|
+
// `../package.json` resolves the same from src/ under tsx and from dist/ built.
|
|
11
|
+
function serverVersion() {
|
|
12
|
+
try {
|
|
13
|
+
const pkg = JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
14
|
+
return typeof pkg.version === 'string' ? pkg.version : '0.0.0';
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return '0.0.0';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
7
20
|
// stdout is the MCP transport. Anything diagnostic goes to stderr or it corrupts
|
|
8
21
|
// the protocol stream.
|
|
9
22
|
function log(message) {
|
|
@@ -12,7 +25,7 @@ function log(message) {
|
|
|
12
25
|
async function main() {
|
|
13
26
|
const db = openDb();
|
|
14
27
|
log(`db ready at ${dbPath()}`);
|
|
15
|
-
const server = new McpServer({ name: 'eklavya', version:
|
|
28
|
+
const server = new McpServer({ name: 'eklavya', version: serverVersion() }, {
|
|
16
29
|
capabilities: { tools: {} },
|
|
17
30
|
instructions: 'Eklavya tracks what this developer has actually learned. Log the concepts your work touches, ' +
|
|
18
31
|
'and quiz from the learner profile rather than from scratch — never ask about a concept already mastered.',
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,iFAAiF;AACjF,uBAAuB;AACvB,SAAS,GAAG,CAAC,OAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,GAAG,CAAC,eAAe,MAAM,EAAE,EAAE,CAAC,CAAC;IAE/B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,gFAAgF;AAChF,2EAA2E;AAC3E,gFAAgF;AAChF,SAAS,aAAa;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7F,OAAO,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,uBAAuB;AACvB,SAAS,GAAG,CAAC,OAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,OAAO,IAAI,CAAC,CAAC;AACrD,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,GAAG,CAAC,eAAe,MAAM,EAAE,EAAE,CAAC,CAAC;IAE/B,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAC7C;QACE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAC3B,YAAY,EACV,+FAA+F;YAC/F,0GAA0G;KAC7G,CACF,CAAC;IAEF,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAE1B,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,IAAI,CAAC;YACH,EAAE,CAAC,KAAK,EAAE,CAAC;QACb,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAEhC,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IACjD,GAAG,CAAC,6BAA6B,CAAC,CAAC;AACrC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,GAAG,CAAC,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/store.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyGrade, initialMastery, SCORE_WINDOW } from './srs.js';
|
|
1
|
+
import { applyGrade, decayedScore, initialMastery, isKnown, SCORE_WINDOW, } from './srs.js';
|
|
2
2
|
export function conceptBySlug(db, slug) {
|
|
3
3
|
return db.prepare('SELECT * FROM concepts WHERE slug = ?').get(slug);
|
|
4
4
|
}
|
|
@@ -119,4 +119,50 @@ export function syncGate(db, sessionId, config, opts = {}) {
|
|
|
119
119
|
updated_at = excluded.updated_at, repo = excluded.repo`).run(sessionId, config.mode, required, answered, passed ? 1 : 0, repo);
|
|
120
120
|
return { mode: config.mode, required, answered, passed, pass_threshold: config.pass_threshold, repo };
|
|
121
121
|
}
|
|
122
|
+
/** The last few questions actually asked about a concept, newest first. */
|
|
123
|
+
export function recentQuestions(db, conceptId, limit = 3) {
|
|
124
|
+
return db
|
|
125
|
+
.prepare(`SELECT question, difficulty AS tier, grade FROM attempts
|
|
126
|
+
WHERE concept_id = ? AND question <> ''
|
|
127
|
+
ORDER BY id DESC LIMIT ?`)
|
|
128
|
+
.all(conceptId, limit);
|
|
129
|
+
}
|
|
130
|
+
/** Loose match: whitespace and punctuation differences are still the same question. */
|
|
131
|
+
export function questionFingerprint(question) {
|
|
132
|
+
return question.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim();
|
|
133
|
+
}
|
|
134
|
+
export function hasAskedQuestion(db, conceptId, question) {
|
|
135
|
+
const target = questionFingerprint(question);
|
|
136
|
+
if (!target)
|
|
137
|
+
return false;
|
|
138
|
+
const rows = db
|
|
139
|
+
.prepare('SELECT question FROM attempts WHERE concept_id = ? ORDER BY id DESC LIMIT 20')
|
|
140
|
+
.all(conceptId);
|
|
141
|
+
return rows.some((r) => questionFingerprint(r.question) === target);
|
|
142
|
+
}
|
|
143
|
+
/** Concepts already asked about in this session — they have had their turn. */
|
|
144
|
+
export function attemptedConceptIds(db, sessionId) {
|
|
145
|
+
const rows = db
|
|
146
|
+
.prepare('SELECT DISTINCT concept_id FROM attempts WHERE session_id = ?')
|
|
147
|
+
.all(sessionId);
|
|
148
|
+
return new Set(rows.map((r) => r.concept_id));
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Prerequisites of a concept the learner has not mastered yet. A tier-3
|
|
152
|
+
* judgement question about a concept whose foundations are missing is not a hard
|
|
153
|
+
* question, it is an unfair one — the tutor needs to see this before asking.
|
|
154
|
+
*/
|
|
155
|
+
export function unmetPrereqs(db, conceptId, now) {
|
|
156
|
+
const rows = db
|
|
157
|
+
.prepare(`SELECT c.slug, m.score, m.reps, m.next_review
|
|
158
|
+
FROM edges e
|
|
159
|
+
JOIN concepts c ON c.id = e.from_concept
|
|
160
|
+
LEFT JOIN mastery m ON m.concept_id = c.id
|
|
161
|
+
WHERE e.to_concept = ? AND e.relation = 'prerequisite_of'
|
|
162
|
+
ORDER BY c.tier ASC, c.slug ASC`)
|
|
163
|
+
.all(conceptId);
|
|
164
|
+
return rows
|
|
165
|
+
.filter((r) => !isKnown({ score: decayedScore(r.score ?? 0, r.next_review, now), reps: r.reps ?? 0 }))
|
|
166
|
+
.map((r) => r.slug);
|
|
167
|
+
}
|
|
122
168
|
//# sourceMappingURL=store.js.map
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -29,6 +29,7 @@ export const setConfig = {
|
|
|
29
29
|
max_questions_per_task: z.number().int().min(1).max(10).optional(),
|
|
30
30
|
min_minutes_between_quizzes: z.number().int().min(0).optional(),
|
|
31
31
|
max_new_concepts_per_session: z.number().int().min(0).max(50).optional(),
|
|
32
|
+
max_stop_blocks_per_session: z.number().int().min(0).max(20).optional(),
|
|
32
33
|
quiet: z.boolean().optional(),
|
|
33
34
|
domains_enabled: z.array(z.string()).optional(),
|
|
34
35
|
},
|
|
@@ -43,6 +44,7 @@ export const setConfig = {
|
|
|
43
44
|
'max_questions_per_task',
|
|
44
45
|
'min_minutes_between_quizzes',
|
|
45
46
|
'max_new_concepts_per_session',
|
|
47
|
+
'max_stop_blocks_per_session',
|
|
46
48
|
'quiet',
|
|
47
49
|
'domains_enabled',
|
|
48
50
|
]) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config_tools.js","sourceRoot":"","sources":["../../src/tools/config_tools.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config_tools.js","sourceRoot":"","sources":["../../src/tools/config_tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,11 +3,13 @@ import { loadConfig, isDomainEnabled } from '../config.js';
|
|
|
3
3
|
import { decayedScore, isKnown, isDue, nextTierToAsk, suggestedTier } from '../srs.js';
|
|
4
4
|
import { CWD_HINT } from './types.js';
|
|
5
5
|
const LIST_CAP = 8;
|
|
6
|
+
/** Mastered concepts are the "don't ask this" list, so it gets more room than the rest. */
|
|
7
|
+
const KNOWN_CAP = 30;
|
|
6
8
|
const WEAK_THRESHOLD = 0.5;
|
|
7
9
|
export const getLearnerProfile = {
|
|
8
10
|
name: 'get_learner_profile',
|
|
9
11
|
title: 'Get learner profile',
|
|
10
|
-
description: 'What this developer already knows. Call before teaching or quizzing so you never ask about a mastered concept. Returns mode, per-domain counts, weak concepts, what is due for review, and the tier to pitch at.',
|
|
12
|
+
description: 'What this developer already knows. Call before teaching or quizzing so you never ask about a mastered concept. Returns mode, per-domain counts, the concepts already mastered, weak concepts, what is due for review, and the tier to pitch at.',
|
|
11
13
|
inputSchema: {
|
|
12
14
|
domain: z.string().optional().describe('Restrict to one domain, e.g. "web-auth".'),
|
|
13
15
|
cwd: z.string().optional().describe(CWD_HINT),
|
|
@@ -28,6 +30,7 @@ export const getLearnerProfile = {
|
|
|
28
30
|
const domains = new Map();
|
|
29
31
|
const knownTiers = [];
|
|
30
32
|
const weak = [];
|
|
33
|
+
const known = [];
|
|
31
34
|
const due = [];
|
|
32
35
|
for (const row of rows) {
|
|
33
36
|
if (!isDomainEnabled(config, row.domain))
|
|
@@ -44,6 +47,9 @@ export const getLearnerProfile = {
|
|
|
44
47
|
if (isKnown({ score, reps })) {
|
|
45
48
|
bucket.known += 1;
|
|
46
49
|
knownTiers.push(row.tier);
|
|
50
|
+
// Named, not just counted: the tutor is told never to re-ask a mastered
|
|
51
|
+
// concept, which it can only honor if it is told which ones those are.
|
|
52
|
+
known.push({ slug: row.slug, score });
|
|
47
53
|
}
|
|
48
54
|
else {
|
|
49
55
|
bucket.learning += 1;
|
|
@@ -65,13 +71,16 @@ export const getLearnerProfile = {
|
|
|
65
71
|
}
|
|
66
72
|
weak.sort((a, b) => a.score - b.score);
|
|
67
73
|
due.sort((a, b) => b.tier - a.tier);
|
|
74
|
+
known.sort((a, b) => b.score - a.score);
|
|
68
75
|
return {
|
|
69
76
|
mode: config.mode,
|
|
70
77
|
domains: [...domains.values()].sort((a, b) => a.domain.localeCompare(b.domain)),
|
|
78
|
+
known: known.slice(0, KNOWN_CAP).map((k) => k.slug),
|
|
79
|
+
known_total: known.length,
|
|
71
80
|
weak: weak.slice(0, LIST_CAP).map((w) => w.slug),
|
|
72
81
|
due_for_review: due.slice(0, LIST_CAP),
|
|
73
82
|
suggested_tier: suggestedTier(knownTiers),
|
|
74
|
-
truncated: weak.length > LIST_CAP || due.length > LIST_CAP,
|
|
83
|
+
truncated: weak.length > LIST_CAP || due.length > LIST_CAP || known.length > KNOWN_CAP,
|
|
75
84
|
};
|
|
76
85
|
},
|
|
77
86
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get_learner_profile.js","sourceRoot":"","sources":["../../src/tools/get_learner_profile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAEpD,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB,MAAM,cAAc,GAAG,GAAG,CAAC;AAe3B,MAAM,CAAC,MAAM,iBAAiB,GAAY;IACxC,IAAI,EAAE,qBAAqB;IAC3B,KAAK,EAAE,qBAAqB;IAC5B,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"get_learner_profile.js","sourceRoot":"","sources":["../../src/tools/get_learner_profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,8 +2,9 @@ import { z } from 'zod';
|
|
|
2
2
|
import { loadConfig } from '../config.js';
|
|
3
3
|
import { decayedScore, isDue, isKnown, nextTierToAsk } from '../srs.js';
|
|
4
4
|
import { resolveSessionId } from '../session.js';
|
|
5
|
-
import { lastAttempt, lastAttemptAt, masteryFor, sessionConcepts } from '../store.js';
|
|
5
|
+
import { attemptedConceptIds, lastAttempt, lastAttemptAt, masteryFor, recentQuestions, sessionConcepts, unmetPrereqs, } from '../store.js';
|
|
6
6
|
import { CWD_HINT, SESSION_HINT } from './types.js';
|
|
7
|
+
const ASKED_HISTORY = 3;
|
|
7
8
|
function minutesSince(iso, now) {
|
|
8
9
|
if (!iso)
|
|
9
10
|
return Number.POSITIVE_INFINITY;
|
|
@@ -16,23 +17,37 @@ function minutesSince(iso, now) {
|
|
|
16
17
|
export const getSessionQuizPlan = {
|
|
17
18
|
name: 'get_session_quiz_plan',
|
|
18
19
|
title: 'Get session quiz plan',
|
|
19
|
-
description: 'What to quiz on right now and at what difficulty tier, chosen from this session\'s concepts and whatever is due for review. Returns questions_needed: 0 when there is nothing worth asking.',
|
|
20
|
+
description: 'What to quiz on right now and at what difficulty tier, chosen from this session\'s concepts and whatever is due for review. Pass a domain to plan a topic quiz instead. Every item carries asked_before (questions this learner has already been asked — never repeat one) and prereqs_unmet. Returns questions_needed: 0 when there is nothing worth asking.',
|
|
20
21
|
inputSchema: {
|
|
21
22
|
session_id: z.string().optional().describe(SESSION_HINT),
|
|
22
23
|
cwd: z.string().optional().describe(CWD_HINT),
|
|
23
24
|
max: z.number().int().min(1).max(10).optional().describe('Cap on questions. Defaults to the configured max_questions_per_task.'),
|
|
25
|
+
domain: z
|
|
26
|
+
.string()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe('Plan a topic quiz on this domain instead of this session\'s work, e.g. "web-auth". Prerequisites are ordered first.'),
|
|
29
|
+
slugs: z
|
|
30
|
+
.array(z.string())
|
|
31
|
+
.optional()
|
|
32
|
+
.describe('Plan around these specific concepts. Use when the developer named a concept rather than a domain.'),
|
|
33
|
+
ignore_cooldown: z
|
|
34
|
+
.boolean()
|
|
35
|
+
.optional()
|
|
36
|
+
.describe('Set true when the developer asked to be quizzed. The cadence limit exists to stop nagging, not to refuse a request.'),
|
|
24
37
|
},
|
|
25
38
|
handler: (args, { db }) => {
|
|
26
39
|
const now = new Date();
|
|
27
40
|
const { config } = loadConfig(args.cwd);
|
|
28
41
|
const sessionId = resolveSessionId(db, args.session_id);
|
|
29
42
|
const max = args.max ?? config.max_questions_per_task;
|
|
43
|
+
const topicMode = Boolean(args.domain || (args.slugs && args.slugs.length > 0));
|
|
30
44
|
if (config.mode === 'off') {
|
|
31
45
|
return { session_id: sessionId, questions_needed: 0, concepts: [], reason: 'mode_off' };
|
|
32
46
|
}
|
|
33
47
|
// Cooldown keeps ambient mode from nagging. It must never apply in enforced
|
|
34
|
-
// mode, or a cooldown could make a commit gate unpassable (decision G5)
|
|
35
|
-
|
|
48
|
+
// mode, or a cooldown could make a commit gate unpassable (decision G5), and
|
|
49
|
+
// it must never override an explicit request (`ignore_cooldown`).
|
|
50
|
+
if (config.mode === 'ambient' && !args.ignore_cooldown) {
|
|
36
51
|
const since = minutesSince(lastAttemptAt(db, sessionId), now);
|
|
37
52
|
if (since < config.min_minutes_between_quizzes) {
|
|
38
53
|
return {
|
|
@@ -47,9 +62,18 @@ export const getSessionQuizPlan = {
|
|
|
47
62
|
const picked = [];
|
|
48
63
|
const seen = new Set();
|
|
49
64
|
const domains = new Set();
|
|
65
|
+
// Concepts already answered in this session have had their turn. Re-offering
|
|
66
|
+
// them is how a learner gets asked the same thing twice in five minutes.
|
|
67
|
+
const alreadyAsked = attemptedConceptIds(db, sessionId);
|
|
68
|
+
let skippedAsked = 0;
|
|
50
69
|
const add = (concept, context, reason) => {
|
|
51
70
|
if (seen.has(concept.slug) || picked.length >= max)
|
|
52
71
|
return;
|
|
72
|
+
if (alreadyAsked.has(concept.id)) {
|
|
73
|
+
seen.add(concept.slug);
|
|
74
|
+
skippedAsked += 1;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
53
77
|
const m = masteryFor(db, concept.id);
|
|
54
78
|
const score = decayedScore(m.score, m.next_review, now);
|
|
55
79
|
const last = lastAttempt(db, concept.id);
|
|
@@ -58,6 +82,7 @@ export const getSessionQuizPlan = {
|
|
|
58
82
|
slug: concept.slug,
|
|
59
83
|
name: concept.name,
|
|
60
84
|
domain: concept.domain,
|
|
85
|
+
description: concept.description,
|
|
61
86
|
tier_to_ask: nextTierToAsk({
|
|
62
87
|
conceptTier: concept.tier,
|
|
63
88
|
lastDifficulty: last?.difficulty ?? null,
|
|
@@ -66,36 +91,104 @@ export const getSessionQuizPlan = {
|
|
|
66
91
|
}),
|
|
67
92
|
context,
|
|
68
93
|
last_grade: last?.grade ?? null,
|
|
94
|
+
asked_before: recentQuestions(db, concept.id, ASKED_HISTORY),
|
|
95
|
+
prereqs_unmet: unmetPrereqs(db, concept.id, now),
|
|
69
96
|
reason,
|
|
70
97
|
});
|
|
71
98
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if (isDue(m.next_review, now))
|
|
86
|
-
add(c, c.context, 'due_review');
|
|
87
|
-
}
|
|
88
|
-
// (c) anything else due in the same domains, so review debt gets paid down
|
|
89
|
-
if (picked.length < max && domains.size > 0) {
|
|
90
|
-
const placeholders = [...domains].map(() => '?').join(',');
|
|
99
|
+
if (topicMode) {
|
|
100
|
+
// Topic quizzes go through the same engine as session quizzes, so a named
|
|
101
|
+
// topic gets the same tier escalation and the same repeat protection.
|
|
102
|
+
const clauses = [];
|
|
103
|
+
const params = [];
|
|
104
|
+
if (args.domain) {
|
|
105
|
+
clauses.push('c.domain = ?');
|
|
106
|
+
params.push(args.domain);
|
|
107
|
+
}
|
|
108
|
+
if (args.slugs && args.slugs.length > 0) {
|
|
109
|
+
clauses.push(`c.slug IN (${args.slugs.map(() => '?').join(',')})`);
|
|
110
|
+
params.push(...args.slugs);
|
|
111
|
+
}
|
|
91
112
|
const rows = db
|
|
92
113
|
.prepare(`SELECT c.* FROM concepts c
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
.all(...
|
|
97
|
-
for
|
|
98
|
-
|
|
114
|
+
LEFT JOIN mastery m ON m.concept_id = c.id
|
|
115
|
+
WHERE (${clauses.join(' OR ')})
|
|
116
|
+
ORDER BY c.tier ASC, c.slug ASC`)
|
|
117
|
+
.all(...params);
|
|
118
|
+
// Weakest and due-for-review first, prerequisites before dependents; a
|
|
119
|
+
// concept they have mastered is only worth asking when review says so.
|
|
120
|
+
const candidates = rows
|
|
121
|
+
.map((c) => {
|
|
122
|
+
const m = masteryFor(db, c.id);
|
|
123
|
+
const score = decayedScore(m.score, m.next_review, now);
|
|
124
|
+
return { c, score, known: isKnown({ score, reps: m.reps }), due: isDue(m.next_review, now) };
|
|
125
|
+
})
|
|
126
|
+
.filter((r) => !r.known || r.due)
|
|
127
|
+
.sort((a, b) => {
|
|
128
|
+
if (a.due !== b.due)
|
|
129
|
+
return a.due ? -1 : 1;
|
|
130
|
+
if (a.score !== b.score)
|
|
131
|
+
return a.score - b.score;
|
|
132
|
+
return a.c.tier - b.c.tier;
|
|
133
|
+
});
|
|
134
|
+
for (const cand of candidates)
|
|
135
|
+
add(cand.c, null, 'topic');
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
const touched = sessionConcepts(db, sessionId);
|
|
139
|
+
for (const c of touched)
|
|
140
|
+
domains.add(c.domain);
|
|
141
|
+
// (a) concepts this session touched that the learner has not mastered
|
|
142
|
+
for (const c of touched) {
|
|
143
|
+
const m = masteryFor(db, c.id);
|
|
144
|
+
const score = decayedScore(m.score, m.next_review, now);
|
|
145
|
+
if (!isKnown({ score, reps: m.reps }))
|
|
146
|
+
add(c, c.context, 'unmastered');
|
|
147
|
+
}
|
|
148
|
+
// (b) concepts this session touched that are due for review
|
|
149
|
+
for (const c of touched) {
|
|
150
|
+
const m = masteryFor(db, c.id);
|
|
151
|
+
if (isDue(m.next_review, now))
|
|
152
|
+
add(c, c.context, 'due_review');
|
|
153
|
+
}
|
|
154
|
+
// (c) anything else due in the same domains, so review debt gets paid down
|
|
155
|
+
if (picked.length < max && domains.size > 0) {
|
|
156
|
+
const placeholders = [...domains].map(() => '?').join(',');
|
|
157
|
+
const rows = db
|
|
158
|
+
.prepare(`SELECT c.* FROM concepts c
|
|
159
|
+
JOIN mastery m ON m.concept_id = c.id
|
|
160
|
+
WHERE c.domain IN (${placeholders}) AND m.next_review IS NOT NULL AND m.next_review <= ?
|
|
161
|
+
ORDER BY m.next_review ASC`)
|
|
162
|
+
.all(...domains, now.toISOString());
|
|
163
|
+
for (const c of rows)
|
|
164
|
+
add(c, null, 'domain_review');
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Foundations before what rests on them, so a quiz never leads with a
|
|
168
|
+
// question the learner has no way to answer.
|
|
169
|
+
picked.sort((a, b) => {
|
|
170
|
+
if (a.prereqs_unmet.length !== b.prereqs_unmet.length) {
|
|
171
|
+
return a.prereqs_unmet.length - b.prereqs_unmet.length;
|
|
172
|
+
}
|
|
173
|
+
return a.tier_to_ask - b.tier_to_ask;
|
|
174
|
+
});
|
|
175
|
+
if (picked.length === 0) {
|
|
176
|
+
// Distinguish "nothing left to ask" from "nothing to ask about" — they
|
|
177
|
+
// need different things said to the developer.
|
|
178
|
+
return skippedAsked > 0
|
|
179
|
+
? {
|
|
180
|
+
session_id: sessionId,
|
|
181
|
+
questions_needed: 0,
|
|
182
|
+
concepts: [],
|
|
183
|
+
reason: 'already_covered',
|
|
184
|
+
detail: `${skippedAsked} concept(s) were already asked about in this session.`,
|
|
185
|
+
}
|
|
186
|
+
: {
|
|
187
|
+
session_id: sessionId,
|
|
188
|
+
questions_needed: 0,
|
|
189
|
+
concepts: [],
|
|
190
|
+
reason: topicMode ? 'no_candidates' : 'nothing_logged',
|
|
191
|
+
};
|
|
99
192
|
}
|
|
100
193
|
return {
|
|
101
194
|
session_id: sessionId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get_session_quiz_plan.js","sourceRoot":"","sources":["../../src/tools/get_session_quiz_plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,
|
|
1
|
+
{"version":3,"file":"get_session_quiz_plan.js","sourceRoot":"","sources":["../../src/tools/get_session_quiz_plan.ts"],"names":[],"mappings":"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"}
|
|
@@ -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, logSessionConcept, syncGate } from '../store.js';
|
|
6
|
+
import { conceptBySlug, gradeConcept, hasAskedQuestion, logSessionConcept, syncGate } from '../store.js';
|
|
7
7
|
import { CWD_HINT, SESSION_HINT } from './types.js';
|
|
8
8
|
export const recordAttempt = {
|
|
9
9
|
name: 'record_attempt',
|
|
@@ -37,6 +37,8 @@ export const recordAttempt = {
|
|
|
37
37
|
detail: 'No concept with that slug. Call upsert_concepts or log_session_concepts first.',
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
+
// Checked before the write, or the question we are recording matches itself.
|
|
41
|
+
const repeatQuestion = hasAskedQuestion(db, concept.id, args.question);
|
|
40
42
|
const state = db.transaction(() => {
|
|
41
43
|
// An attempt on a concept the session never logged still counts toward the
|
|
42
44
|
// gate, so quizzing on review debt is not free.
|
|
@@ -62,6 +64,9 @@ export const recordAttempt = {
|
|
|
62
64
|
reps: state.reps,
|
|
63
65
|
ease: Number(state.ease.toFixed(2)),
|
|
64
66
|
known: isKnown({ score, reps: state.reps }),
|
|
67
|
+
// PRD goal 2. Recorded either way — refusing the write would lose a real
|
|
68
|
+
// answer — but the tutor is told, so the next question can be a new one.
|
|
69
|
+
repeat_question: repeatQuestion,
|
|
65
70
|
gate,
|
|
66
71
|
};
|
|
67
72
|
},
|
|
@@ -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,EAAE,aAAa,EAAE,YAAY,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"record_attempt.js","sourceRoot":"","sources":["../../src/tools/record_attempt.ts"],"names":[],"mappings":"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"}
|