eklavya-mcp 1.6.1 → 1.7.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/bin/eklavya-mcp.sh +1 -1
- package/dist/ask.js +26 -10
- package/dist/ask.js.map +1 -1
- package/dist/assets/dashboard.html +407 -0
- package/dist/assets/tokens.css +135 -0
- package/dist/assets/tutor-skill.md +4 -1
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -1
- package/dist/dashboard.js +214 -0
- package/dist/dashboard.js.map +1 -0
- package/dist/tools/get_learner_profile.js +39 -1
- package/dist/tools/get_learner_profile.js.map +1 -1
- package/dist/tools/get_session_quiz_plan.js +15 -0
- package/dist/tools/get_session_quiz_plan.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.
|
|
15
|
+
PINNED_VERSION="1.7.0"
|
|
16
16
|
|
|
17
17
|
MCP_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
|
18
18
|
LOCAL_SERVER="$MCP_DIR/dist/server.js"
|
package/dist/ask.js
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
/** Blank line between stem and footer, so the two never read as one sentence. */
|
|
2
2
|
export const FOOTER_GAP = '\n\n';
|
|
3
|
+
/** What each tier is actually asking for, so `tier 4` is not a bare number. */
|
|
4
|
+
const TIER_LABEL = {
|
|
5
|
+
1: 'recall',
|
|
6
|
+
2: 'mechanism',
|
|
7
|
+
3: 'judgement',
|
|
8
|
+
4: 'failure modes',
|
|
9
|
+
5: 'design',
|
|
10
|
+
};
|
|
3
11
|
/**
|
|
4
12
|
* `null` when nothing should be shown.
|
|
5
13
|
*
|
|
@@ -8,21 +16,29 @@ export const FOOTER_GAP = '\n\n';
|
|
|
8
16
|
*
|
|
9
17
|
* `cadence` is deliberately absent. The question's *arrival* -- mid-task or at
|
|
10
18
|
* the end -- already tells them when Eklavya asks, and a footer that repeats what
|
|
11
|
-
* the moment just demonstrated is noise.
|
|
12
|
-
*
|
|
13
|
-
*
|
|
19
|
+
* the moment just demonstrated is noise. Everything else is here: the mode, the
|
|
20
|
+
* focus, the level, what the tier is asking for, and how many questions are
|
|
21
|
+
* coming. A learner who cannot see those is answering a question with no idea
|
|
22
|
+
* why it was pitched where it was, or whether four more follow.
|
|
14
23
|
*/
|
|
15
|
-
export function askFooter({ config, level, pinned, tier }) {
|
|
24
|
+
export function askFooter({ config, level, pinned, tier, position }) {
|
|
16
25
|
if (config.quiet)
|
|
17
26
|
return null;
|
|
18
27
|
const focus = config.focus === 'learn' && config.focus_topic
|
|
19
28
|
? `learn: ${config.focus_topic}`
|
|
20
29
|
: config.focus;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
const label = TIER_LABEL[tier];
|
|
31
|
+
const parts = [
|
|
32
|
+
// `enforced` is the one value with a consequence attached, so it says so.
|
|
33
|
+
config.mode === 'enforced' ? 'enforced (gated)' : config.mode,
|
|
34
|
+
focus,
|
|
35
|
+
// A pinned level explains itself here or nowhere: without it, questions
|
|
36
|
+
// simply stop getting harder one day and nothing on screen says why.
|
|
37
|
+
pinned ? `${level} (pinned)` : level,
|
|
38
|
+
label ? `tier ${tier} ${label}` : `tier ${tier}`,
|
|
39
|
+
];
|
|
40
|
+
if (position && position.total > 1)
|
|
41
|
+
parts.push(`q ${position.index}/${position.total}`);
|
|
26
42
|
return parts.join(' · ');
|
|
27
43
|
}
|
|
28
44
|
/**
|
|
@@ -35,7 +51,7 @@ export function askFooter({ config, level, pinned, tier }) {
|
|
|
35
51
|
* level or the focus changed, which is precisely the failure migration 006 kept
|
|
36
52
|
* the options out of the stem to avoid.
|
|
37
53
|
*/
|
|
38
|
-
const FOOTER_LINE = /\n[ \t]*(?:project|concept|learn(?::[^\n·]*)?)[ \t]*·[ \t]*(?:easy|medium|hard)(?:[ \t]*\(pinned\))?[ \t]*·[ \t]*tier[ \t]*[1-5]
|
|
54
|
+
const FOOTER_LINE = /\n[ \t]*(?:(?:off|ambient|enforced(?:[ \t]*\(gated\))?)[ \t]*·[ \t]*)?(?:project|concept|learn(?::[^\n·]*)?)[ \t]*·[ \t]*(?:easy|medium|hard)(?:[ \t]*\(pinned\))?[ \t]*·[ \t]*tier[ \t]*[1-5][^\n]*$/i;
|
|
39
55
|
export function stripAskFooter(question) {
|
|
40
56
|
return question.replace(FOOTER_LINE, '').trimEnd();
|
|
41
57
|
}
|
package/dist/ask.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../src/ask.ts"],"names":[],"mappings":"AA0BA,iFAAiF;AACjF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"ask.js","sourceRoot":"","sources":["../src/ask.ts"],"names":[],"mappings":"AA0BA,iFAAiF;AACjF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AAajC,+EAA+E;AAC/E,MAAM,UAAU,GAA2B;IACzC,CAAC,EAAE,QAAQ;IACX,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,WAAW;IACd,CAAC,EAAE,eAAe;IAClB,CAAC,EAAE,QAAQ;CACZ,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAkB;IACjF,IAAI,MAAM,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAE9B,MAAM,KAAK,GACT,MAAM,CAAC,KAAK,KAAK,OAAO,IAAI,MAAM,CAAC,WAAW;QAC5C,CAAC,CAAC,UAAU,MAAM,CAAC,WAAW,EAAE;QAChC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;IAEnB,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG;QACZ,0EAA0E;QAC1E,MAAM,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI;QAC7D,KAAK;QACL,wEAAwE;QACxE,qEAAqE;QACrE,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK;QACpC,KAAK,CAAC,CAAC,CAAC,QAAQ,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE;KACjD,CAAC;IACF,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,KAAK,QAAQ,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAExF,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,GACf,wMAAwM,CAAC;AAE3M,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,OAAO,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Eklavya — learning progress</title>
|
|
7
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Crect width='24' height='24' rx='5' fill='%23049D66'/%3E%3Cg fill='none' stroke='%23fff' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M7 5a11 11 0 0 1 0 14'/%3E%3Cpath d='M6 12h12'/%3E%3Cpath d='M14 9l3 3-3 3'/%3E%3C/g%3E%3C/svg%3E">
|
|
8
|
+
<link rel="stylesheet" href="/tokens.css">
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
+
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
12
|
+
<style>
|
|
13
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
14
|
+
body { margin:0; font-family:var(--font-sans); background:var(--bg-subtle); color:var(--fg);
|
|
15
|
+
font-size:var(--text-base); line-height:var(--lh-base); }
|
|
16
|
+
.wrap { max-width:1140px; margin:0 auto; padding:0 var(--space-8); }
|
|
17
|
+
code, .mono { font-family:var(--font-mono); font-size:var(--text-sm); }
|
|
18
|
+
|
|
19
|
+
/* ---------- header ---------- */
|
|
20
|
+
header { background:var(--neutral-900); color:var(--on-dark); padding:var(--space-8) 0 var(--space-10); }
|
|
21
|
+
.bar { display:flex; align-items:center; gap:var(--space-4); flex-wrap:wrap; }
|
|
22
|
+
.mark { width:36px; height:36px; border-radius:var(--radius-md); background:var(--brand);
|
|
23
|
+
display:grid; place-items:center; flex:none; }
|
|
24
|
+
h1 { font-size:var(--text-xl); font-weight:var(--weight-bold); letter-spacing:-.02em; margin:0; }
|
|
25
|
+
.sub { color:var(--on-dark-muted); font-size:var(--text-sm); margin:2px 0 0; }
|
|
26
|
+
.spacer { flex:1 1 auto; }
|
|
27
|
+
select { font:inherit; font-size:var(--text-sm); background:var(--neutral-800); color:var(--on-dark);
|
|
28
|
+
border:1px solid var(--neutral-700); border-radius:var(--radius-md);
|
|
29
|
+
padding:var(--space-2) var(--space-3); }
|
|
30
|
+
select:focus-visible { outline:none; box-shadow:var(--ring); }
|
|
31
|
+
|
|
32
|
+
/* ---------- stat tiles ---------- */
|
|
33
|
+
.tiles { display:grid; grid-template-columns:repeat(4,1fr); gap:var(--space-4); margin-top:var(--space-6); }
|
|
34
|
+
.tile { background:var(--neutral-800); border:1px solid var(--neutral-700); border-radius:var(--radius-lg);
|
|
35
|
+
padding:var(--space-5); }
|
|
36
|
+
.tile .k { font-size:var(--text-xs); font-weight:var(--weight-bold); letter-spacing:.08em;
|
|
37
|
+
text-transform:uppercase; color:var(--on-dark-muted); }
|
|
38
|
+
.tile .v { font-size:var(--text-3xl); font-weight:var(--weight-extra,800); letter-spacing:-.025em;
|
|
39
|
+
line-height:1.1; margin-top:var(--space-2); }
|
|
40
|
+
.tile .n { font-size:var(--text-sm); color:var(--on-dark-muted); margin-top:var(--space-1); }
|
|
41
|
+
.good { color:var(--green-300); }
|
|
42
|
+
|
|
43
|
+
/* ---------- cards ---------- */
|
|
44
|
+
main { padding:var(--space-10) 0 var(--space-20); }
|
|
45
|
+
section { background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-lg);
|
|
46
|
+
padding:var(--space-6); margin-bottom:var(--space-6); }
|
|
47
|
+
h2 { font-size:var(--text-md); font-weight:var(--weight-bold); letter-spacing:-.01em; margin:0; }
|
|
48
|
+
.hint { color:var(--fg-subtle); font-size:var(--text-sm); margin:var(--space-1) 0 var(--space-5); }
|
|
49
|
+
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:var(--space-6); }
|
|
50
|
+
.grid2 > section { margin:0; }
|
|
51
|
+
|
|
52
|
+
/* ---------- tables ---------- */
|
|
53
|
+
table { width:100%; border-collapse:collapse; font-size:var(--text-sm); }
|
|
54
|
+
th { text-align:left; font-size:var(--text-xs); font-weight:var(--weight-bold); letter-spacing:.08em;
|
|
55
|
+
text-transform:uppercase; color:var(--fg-subtle); padding:0 var(--space-3) var(--space-2) 0;
|
|
56
|
+
border-bottom:1px solid var(--border); white-space:nowrap; }
|
|
57
|
+
td { padding:var(--space-3) var(--space-3) var(--space-3) 0; border-bottom:1px solid var(--border);
|
|
58
|
+
vertical-align:top; }
|
|
59
|
+
tr:last-child td { border-bottom:none; }
|
|
60
|
+
.num { text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap; }
|
|
61
|
+
.scroll { overflow-x:auto; }
|
|
62
|
+
|
|
63
|
+
/* ---------- meters (sequential, one hue) ---------- */
|
|
64
|
+
.meter { height:8px; border-radius:var(--radius-pill); background:var(--bg-sunken); overflow:hidden;
|
|
65
|
+
min-width:80px; }
|
|
66
|
+
.meter > i { display:block; height:100%; background:var(--brand); border-radius:var(--radius-pill); }
|
|
67
|
+
.meter.warn > i { background:var(--warning); }
|
|
68
|
+
|
|
69
|
+
/* ---------- chart ---------- */
|
|
70
|
+
.legend { display:flex; gap:var(--space-5); font-size:var(--text-sm); color:var(--fg-muted);
|
|
71
|
+
margin-bottom:var(--space-4); flex-wrap:wrap; }
|
|
72
|
+
.legend b { display:inline-block; width:10px; height:10px; border-radius:3px; margin-right:var(--space-2); }
|
|
73
|
+
.chart { position:relative; }
|
|
74
|
+
.chart svg { display:block; width:100%; height:200px; overflow:visible; }
|
|
75
|
+
.gridline { stroke:var(--border); stroke-width:1; }
|
|
76
|
+
.axis { font-family:var(--font-mono); font-size:10px; fill:var(--fg-faint); }
|
|
77
|
+
.hit { fill:transparent; cursor:pointer; }
|
|
78
|
+
.hit:hover + .col, .hit:focus-visible + .col { opacity:.75; }
|
|
79
|
+
.tip { position:absolute; pointer-events:none; opacity:0; transform:translate(-50%,-100%);
|
|
80
|
+
background:var(--neutral-900); color:var(--on-dark); border-radius:var(--radius-md);
|
|
81
|
+
padding:var(--space-3); font-size:var(--text-xs); line-height:1.6; white-space:nowrap;
|
|
82
|
+
box-shadow:var(--shadow-md); transition:opacity var(--duration-fast) var(--ease); z-index:2; }
|
|
83
|
+
.tip.on { opacity:1; }
|
|
84
|
+
.tip .r { display:flex; justify-content:space-between; gap:var(--space-4); }
|
|
85
|
+
|
|
86
|
+
/* ---------- pills & misc ---------- */
|
|
87
|
+
.pill { display:inline-block; font-family:var(--font-mono); font-size:var(--text-xs);
|
|
88
|
+
padding:2px 8px; border-radius:var(--radius-pill); background:var(--bg-sunken);
|
|
89
|
+
color:var(--fg-muted); white-space:nowrap; }
|
|
90
|
+
.pill.due { background:var(--warning-bg); color:#8a5600; }
|
|
91
|
+
.pill.ok { background:var(--brand-subtle); color:var(--green-700); }
|
|
92
|
+
.ctx { color:var(--fg); }
|
|
93
|
+
.slug { font-family:var(--font-mono); font-size:var(--text-xs); color:var(--fg-subtle); }
|
|
94
|
+
.empty { color:var(--fg-subtle); font-size:var(--text-sm); }
|
|
95
|
+
footer { color:var(--fg-subtle); font-size:var(--text-sm); text-align:center; padding-bottom:var(--space-10); }
|
|
96
|
+
|
|
97
|
+
@media (max-width:900px) {
|
|
98
|
+
.tiles { grid-template-columns:repeat(2,1fr); }
|
|
99
|
+
.grid2 { grid-template-columns:1fr; }
|
|
100
|
+
}
|
|
101
|
+
@media (max-width:560px) {
|
|
102
|
+
.wrap { padding:0 var(--space-4); }
|
|
103
|
+
.tiles { grid-template-columns:1fr 1fr; gap:var(--space-3); }
|
|
104
|
+
.tile .v { font-size:var(--text-2xl); }
|
|
105
|
+
}
|
|
106
|
+
@media (prefers-reduced-motion:reduce) { * { transition:none !important; animation:none !important; } }
|
|
107
|
+
</style>
|
|
108
|
+
</head>
|
|
109
|
+
<body>
|
|
110
|
+
<header>
|
|
111
|
+
<div class="wrap">
|
|
112
|
+
<div class="bar">
|
|
113
|
+
<div class="mark" aria-hidden="true">
|
|
114
|
+
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="1.8"
|
|
115
|
+
stroke-linecap="round" stroke-linejoin="round">
|
|
116
|
+
<path d="M5 3a13 13 0 0 1 0 18"/><path d="M5 3l14 9L5 21"/><path d="M3 12h18"/><path d="M15 8l4 4-4 4"/>
|
|
117
|
+
</svg>
|
|
118
|
+
</div>
|
|
119
|
+
<div>
|
|
120
|
+
<h1>Learning progress</h1>
|
|
121
|
+
<p class="sub" id="sub">Loading…</p>
|
|
122
|
+
</div>
|
|
123
|
+
<div class="spacer"></div>
|
|
124
|
+
<label class="sub" for="proj">Project</label>
|
|
125
|
+
<select id="proj"><option value="*">All projects</option></select>
|
|
126
|
+
</div>
|
|
127
|
+
<div class="tiles" id="tiles"></div>
|
|
128
|
+
</div>
|
|
129
|
+
</header>
|
|
130
|
+
|
|
131
|
+
<main class="wrap">
|
|
132
|
+
<section>
|
|
133
|
+
<h2>Answers over the last 30 days</h2>
|
|
134
|
+
<p class="hint" id="chart-hint">Right, missed and skipped, per day.</p>
|
|
135
|
+
<div class="legend">
|
|
136
|
+
<span><b style="background:var(--green-600)"></b>Right</span>
|
|
137
|
+
<span><b style="background:var(--warning)"></b>Missed</span>
|
|
138
|
+
<span><b style="background:var(--neutral-400)"></b>Skipped</span>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="chart"><div class="tip" id="tip"></div><svg id="chart" role="img"
|
|
141
|
+
aria-label="Daily answers, split into right, missed and skipped"></svg></div>
|
|
142
|
+
</section>
|
|
143
|
+
|
|
144
|
+
<div class="grid2">
|
|
145
|
+
<section>
|
|
146
|
+
<h2>Projects</h2>
|
|
147
|
+
<p class="hint">Where the learning is happening, and how it is going there.</p>
|
|
148
|
+
<div class="scroll"><table id="projects"></table></div>
|
|
149
|
+
</section>
|
|
150
|
+
<section>
|
|
151
|
+
<h2>Domains</h2>
|
|
152
|
+
<p class="hint">Mastered out of what you have actually touched. The catalogue is a library, not a to-do list.</p>
|
|
153
|
+
<div class="scroll"><table id="domains"></table></div>
|
|
154
|
+
</section>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<section>
|
|
158
|
+
<h2>What these sessions taught you</h2>
|
|
159
|
+
<p class="hint">The real code each concept came from — the memory the slug hangs on.</p>
|
|
160
|
+
<div class="scroll"><table id="recent"></table></div>
|
|
161
|
+
</section>
|
|
162
|
+
|
|
163
|
+
<section>
|
|
164
|
+
<h2>Skipped</h2>
|
|
165
|
+
<p class="hint">Declined or blanked. They come back a tier lower — a backlog, not a scolding.</p>
|
|
166
|
+
<div class="scroll"><table id="skipped"></table></div>
|
|
167
|
+
</section>
|
|
168
|
+
|
|
169
|
+
<section>
|
|
170
|
+
<h2>Every concept you have been asked</h2>
|
|
171
|
+
<p class="hint">Weakest first. Score decays until you see it again.</p>
|
|
172
|
+
<div class="scroll"><table id="concepts"></table></div>
|
|
173
|
+
</section>
|
|
174
|
+
</main>
|
|
175
|
+
|
|
176
|
+
<footer class="wrap">
|
|
177
|
+
Read from <code id="dbline">~/.eklavya/knowledge.db</code> — nothing on this page leaves your machine.
|
|
178
|
+
</footer>
|
|
179
|
+
|
|
180
|
+
<script>
|
|
181
|
+
const $ = (id) => document.getElementById(id);
|
|
182
|
+
const esc = (s) => String(s ?? '').replace(/[&<>"]/g, (c) => ({'&':'&','<':'<','>':'>','"':'"'}[c]));
|
|
183
|
+
const base = (p) => (p ? p.split('/').filter(Boolean).pop() : 'unattributed');
|
|
184
|
+
const pct = (n, d) => (d ? Math.round((n / d) * 100) : 0);
|
|
185
|
+
const day = (s) => new Date(s + 'T00:00:00').toLocaleDateString(undefined, { month:'short', day:'numeric' });
|
|
186
|
+
const ago = (ts) => {
|
|
187
|
+
const d = Math.floor((Date.now() - new Date(ts.replace(' ', 'T') + 'Z')) / 86400000);
|
|
188
|
+
return d <= 0 ? 'today' : d === 1 ? 'yesterday' : d + ' days ago';
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
let STATE = null;
|
|
192
|
+
let FILTER = '*';
|
|
193
|
+
|
|
194
|
+
const inScope = (repo) => FILTER === '*' || (repo ?? '') === (FILTER === '~' ? '' : FILTER);
|
|
195
|
+
|
|
196
|
+
function rows(t, head, body) {
|
|
197
|
+
t.innerHTML = body.length
|
|
198
|
+
? '<thead><tr>' + head.map((h) => `<th${h.n ? ' class="num"' : ''}>${esc(h.t)}</th>`).join('') + '</tr></thead>'
|
|
199
|
+
+ '<tbody>' + body.join('') + '</tbody>'
|
|
200
|
+
: '<tbody><tr><td class="empty">Nothing here yet.</td></tr></tbody>';
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function renderTiles() {
|
|
204
|
+
const t = STATE.totals;
|
|
205
|
+
const scoped = STATE.projects.filter((p) => inScope(p.repo));
|
|
206
|
+
const answers = scoped.reduce((a, p) => a + p.answers, 0);
|
|
207
|
+
const passed = scoped.reduce((a, p) => a + p.passed, 0);
|
|
208
|
+
const skipped = scoped.reduce((a, p) => a + p.skipped, 0);
|
|
209
|
+
const due = STATE.concepts.filter((c) => c.due && inScope(c.repo)).length;
|
|
210
|
+
const mastered = STATE.concepts.filter((c) => c.mastered && inScope(c.repo)).length;
|
|
211
|
+
const tiles = [
|
|
212
|
+
['Accuracy', answers ? pct(passed, answers) + '%' : '—', `${passed} right of ${answers} answered`, passed && pct(passed, answers) >= 70],
|
|
213
|
+
['Mastered', mastered, `of ${STATE.concepts.filter((c) => inScope(c.repo)).length} concepts asked`, mastered > 0],
|
|
214
|
+
['Due now', due, due ? 'run /eklavya:quiz' : 'nothing waiting', false],
|
|
215
|
+
['Skipped', skipped, skipped ? 'waiting a tier lower' : 'none ducked', false],
|
|
216
|
+
];
|
|
217
|
+
$('tiles').innerHTML = tiles.map(([k, v, n, good]) =>
|
|
218
|
+
`<div class="tile"><div class="k">${k}</div><div class="v${good ? ' good' : ''}">${esc(v)}</div><div class="n">${esc(n)}</div></div>`).join('');
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function renderChart() {
|
|
222
|
+
const byDay = new Map();
|
|
223
|
+
for (const d of STATE.timeline) {
|
|
224
|
+
if (!inScope(d.repo)) continue;
|
|
225
|
+
const cur = byDay.get(d.day) ?? { day: d.day, passed: 0, missed: 0, skipped: 0 };
|
|
226
|
+
cur.passed += d.passed; cur.missed += d.missed; cur.skipped += d.skipped;
|
|
227
|
+
byDay.set(d.day, cur);
|
|
228
|
+
}
|
|
229
|
+
const svg = $('chart');
|
|
230
|
+
if (!byDay.size) {
|
|
231
|
+
svg.innerHTML = '<text x="0" y="24" class="axis">No answers in this window.</text>';
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// A real date axis: every day in the window gets a slot, including the empty
|
|
235
|
+
// ones. Plotting only the days that have data would space three sessions
|
|
236
|
+
// evenly across a month and hide the gaps, which are the honest part.
|
|
237
|
+
const days = [];
|
|
238
|
+
const cursor = new Date();
|
|
239
|
+
cursor.setUTCHours(0, 0, 0, 0);
|
|
240
|
+
cursor.setUTCDate(cursor.getUTCDate() - (STATE.timeline_days - 1));
|
|
241
|
+
for (let i = 0; i < STATE.timeline_days; i++) {
|
|
242
|
+
const key = cursor.toISOString().slice(0, 10);
|
|
243
|
+
days.push(byDay.get(key) ?? { day: key, passed: 0, missed: 0, skipped: 0 });
|
|
244
|
+
cursor.setUTCDate(cursor.getUTCDate() + 1);
|
|
245
|
+
}
|
|
246
|
+
// The viewBox tracks the container's real pixel width so the SVG renders 1:1.
|
|
247
|
+
// A fixed 1000-wide viewBox scaled to a 520px card would shrink the 10px axis
|
|
248
|
+
// text to five, which is the whole reason the chart is redrawn on resize.
|
|
249
|
+
const W = Math.max(320, svg.parentElement.clientWidth || 1000);
|
|
250
|
+
const H = 200, PAD_B = 22, PAD_L = 24;
|
|
251
|
+
const max = Math.max(...days.map((d) => d.passed + d.missed + d.skipped), 1);
|
|
252
|
+
const step = (W - PAD_L) / days.length;
|
|
253
|
+
const bw = Math.min(28, Math.max(6, step - 6));
|
|
254
|
+
const y = (v) => (H - PAD_B) - (v / max) * (H - PAD_B - 8);
|
|
255
|
+
const GAP = 2; // surface gap between stacked segments
|
|
256
|
+
|
|
257
|
+
let out = '';
|
|
258
|
+
for (let i = 0; i <= 2; i++) {
|
|
259
|
+
const v = Math.round((max / 2) * i);
|
|
260
|
+
out += `<line class="gridline" x1="${PAD_L}" x2="${W}" y1="${y(v)}" y2="${y(v)}"/>`
|
|
261
|
+
+ `<text class="axis" x="0" y="${y(v) + 3}">${v}</text>`;
|
|
262
|
+
}
|
|
263
|
+
// Stack order is fixed: right at the base, then missed, then skipped on top.
|
|
264
|
+
// Segment colour never depends on rank, only on which measure it is.
|
|
265
|
+
const SEGMENTS = [['passed', 'var(--green-600)'], ['missed', 'var(--warning)'], ['skipped', 'var(--neutral-400)']];
|
|
266
|
+
const labelEvery = Math.max(1, Math.ceil(46 / step));
|
|
267
|
+
days.forEach((d, i) => {
|
|
268
|
+
const x = PAD_L + i * step + (step - bw) / 2;
|
|
269
|
+
let acc = 0, seg = '', topColor = 'var(--green-600)';
|
|
270
|
+
for (const [key, color] of SEGMENTS) {
|
|
271
|
+
if (!d[key]) continue;
|
|
272
|
+
const h = (d[key] / max) * (H - PAD_B - 8);
|
|
273
|
+
// A 2px surface gap between stacked fills, taken off the upper segment
|
|
274
|
+
// so the bar's total height still reads as the day's total.
|
|
275
|
+
const inset = acc ? GAP : 0;
|
|
276
|
+
seg += `<rect x="${x}" y="${y(acc) - h + inset}" width="${bw}" height="${Math.max(1, h - inset)}" fill="${color}"/>`;
|
|
277
|
+
acc += d[key];
|
|
278
|
+
topColor = color;
|
|
279
|
+
}
|
|
280
|
+
// 4px rounded cap on the top of the stack only; the base stays square on the
|
|
281
|
+
// axis. A day with no answers draws nothing at all — a cap on an empty stack
|
|
282
|
+
// is a mark sitting on the baseline, which reads as data that is not there.
|
|
283
|
+
const hit = `<rect class="hit" x="${PAD_L + i * step}" y="0" width="${step}" height="${H - PAD_B}" data-i="${i}" tabindex="0"/>`;
|
|
284
|
+
const cap = acc ? `<rect x="${x}" y="${y(acc)}" width="${bw}" height="4" rx="2" fill="${topColor}"/>` : '';
|
|
285
|
+
out += hit + `<g class="col">${seg}${cap}</g>`;
|
|
286
|
+
// Ends always get a label; strided ones stand down near the right edge
|
|
287
|
+
// rather than colliding with the last date.
|
|
288
|
+
if (i === 0 || i === days.length - 1 || (i % labelEvery === 0 && i < days.length - labelEvery)) {
|
|
289
|
+
out += `<text class="axis" x="${x + bw / 2}" text-anchor="middle" y="${H - 6}">${day(d.day)}</text>`;
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
svg.setAttribute('viewBox', `0 0 ${W} ${H}`);
|
|
293
|
+
svg.innerHTML = out;
|
|
294
|
+
|
|
295
|
+
const tip = $('tip');
|
|
296
|
+
svg.querySelectorAll('.hit').forEach((hit) => {
|
|
297
|
+
const show = () => {
|
|
298
|
+
const d = days[+hit.dataset.i];
|
|
299
|
+
tip.innerHTML = `<div class="mono">${esc(day(d.day))}</div>`
|
|
300
|
+
+ [['Right', d.passed], ['Missed', d.missed], ['Skipped', d.skipped]]
|
|
301
|
+
.map(([k, v]) => `<div class="r"><span>${k}</span><span>${v}</span></div>`).join('');
|
|
302
|
+
const r = hit.getBoundingClientRect(), p = svg.parentElement.getBoundingClientRect();
|
|
303
|
+
tip.style.left = (r.left - p.left + r.width / 2) + 'px';
|
|
304
|
+
tip.style.top = (r.top - p.top - 8) + 'px';
|
|
305
|
+
tip.classList.add('on');
|
|
306
|
+
};
|
|
307
|
+
hit.addEventListener('mouseenter', show);
|
|
308
|
+
hit.addEventListener('focus', show);
|
|
309
|
+
hit.addEventListener('mouseleave', () => tip.classList.remove('on'));
|
|
310
|
+
hit.addEventListener('blur', () => tip.classList.remove('on'));
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function renderProjects() {
|
|
315
|
+
const body = STATE.projects.filter((p) => inScope(p.repo)).map((p) => {
|
|
316
|
+
const acc = pct(p.passed, p.answers);
|
|
317
|
+
return `<tr><td><strong>${esc(base(p.repo))}</strong><div class="slug">${esc(p.repo ?? 'recorded before projects were tracked')}</div></td>`
|
|
318
|
+
+ `<td><span class="pill">${esc(p.level)}</span></td>`
|
|
319
|
+
+ `<td class="num">${p.answers}</td>`
|
|
320
|
+
+ `<td style="min-width:120px"><div class="meter${acc < 70 ? ' warn' : ''}"><i style="width:${acc}%"></i></div>
|
|
321
|
+
<div class="slug">${acc}% right</div></td>`
|
|
322
|
+
+ `<td class="num slug">${esc(ago(p.last_active))}</td></tr>`;
|
|
323
|
+
});
|
|
324
|
+
rows($('projects'), [{t:'Project'},{t:'Level'},{t:'Answers',n:1},{t:'Accuracy'},{t:'Last',n:1}], body);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function renderDomains() {
|
|
328
|
+
// Recomputed from the scoped concept list rather than read off the server's
|
|
329
|
+
// totals, so picking a project moves this card too. `unseen` stays
|
|
330
|
+
// catalogue-wide on purpose: the seed graph does not belong to a repo.
|
|
331
|
+
const touchedBy = new Map();
|
|
332
|
+
for (const c of STATE.concepts) {
|
|
333
|
+
if (!inScope(c.repo)) continue;
|
|
334
|
+
const d = touchedBy.get(c.domain) ?? { domain: c.domain, mastered: 0, learning: 0, unseen: 0 };
|
|
335
|
+
d[c.mastered ? 'mastered' : 'learning'] += 1;
|
|
336
|
+
touchedBy.set(c.domain, d);
|
|
337
|
+
}
|
|
338
|
+
for (const d of STATE.domains) {
|
|
339
|
+
const row = touchedBy.get(d.domain);
|
|
340
|
+
if (row) row.unseen = d.unseen;
|
|
341
|
+
}
|
|
342
|
+
const body = [...touchedBy.values()]
|
|
343
|
+
.sort((a, b) => b.mastered + b.learning - (a.mastered + a.learning))
|
|
344
|
+
.map((d) => {
|
|
345
|
+
const touched = d.mastered + d.learning;
|
|
346
|
+
return `<tr><td><strong>${esc(d.domain)}</strong></td>`
|
|
347
|
+
+ `<td style="min-width:120px"><div class="meter"><i style="width:${pct(d.mastered, touched)}%"></i></div>
|
|
348
|
+
<div class="slug">${d.mastered} of ${touched} touched</div></td>`
|
|
349
|
+
+ `<td class="num slug">${d.unseen} not seen</td></tr>`;
|
|
350
|
+
});
|
|
351
|
+
rows($('domains'), [{t:'Domain'},{t:'Mastered'},{t:'Catalogue',n:1}], body);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function renderRecent() {
|
|
355
|
+
const body = STATE.recent.filter((r) => inScope(r.repo)).slice(0, 20).map((r) =>
|
|
356
|
+
`<tr><td class="ctx">${esc(r.context)}<div class="slug">${esc(r.slug)} · ${esc(base(r.repo))}</div></td>`
|
|
357
|
+
+ `<td class="num slug">${esc(ago(r.ts))}</td></tr>`);
|
|
358
|
+
rows($('recent'), [{t:'What you did'},{t:'When',n:1}], body);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function renderSkipped() {
|
|
362
|
+
const body = STATE.skipped.filter((s) => inScope(s.repo)).map((s) =>
|
|
363
|
+
`<tr><td><strong>${esc(s.name)}</strong><div class="slug">${esc(s.slug)}</div></td>`
|
|
364
|
+
+ `<td><span class="pill">${s.outcome === 'declined' ? 'declined' : 'blanked'}</span></td>`
|
|
365
|
+
+ `<td class="ctx">${esc(s.question ?? '')}</td>`
|
|
366
|
+
+ `<td class="num slug">${esc(ago(s.ts))}</td></tr>`);
|
|
367
|
+
rows($('skipped'), [{t:'Concept'},{t:'How'},{t:'The question'},{t:'When',n:1}], body);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function renderConcepts() {
|
|
371
|
+
const body = STATE.concepts.filter((c) => inScope(c.repo)).map((c) =>
|
|
372
|
+
`<tr><td><strong>${esc(c.name)}</strong><div class="slug">${esc(c.slug)} · ${esc(c.domain)} · T${c.tier}</div></td>`
|
|
373
|
+
+ `<td style="min-width:110px"><div class="meter${c.score < 0.5 ? ' warn' : ''}"><i style="width:${Math.round(c.score * 100)}%"></i></div>
|
|
374
|
+
<div class="slug">${Math.round(c.score * 100)}%</div></td>`
|
|
375
|
+
+ `<td class="num">${c.attempts}</td>`
|
|
376
|
+
+ `<td>${c.mastered ? '<span class="pill ok">mastered</span>' : c.due ? '<span class="pill due">due</span>' : '<span class="pill">learning</span>'}</td>`
|
|
377
|
+
+ `<td class="ctx">${esc(c.context ?? '')}</td></tr>`);
|
|
378
|
+
rows($('concepts'), [{t:'Concept'},{t:'Score'},{t:'Asked',n:1},{t:'State'},{t:'From your code'}], body);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function renderAll() {
|
|
382
|
+
const scoped = STATE.concepts.filter((c) => inScope(c.repo));
|
|
383
|
+
const answers = STATE.projects.filter((p) => inScope(p.repo)).reduce((a, p) => a + p.answers, 0);
|
|
384
|
+
const where = FILTER === '*' ? 'across all projects' : 'in ' + base(FILTER === '~' ? null : FILTER);
|
|
385
|
+
const n = (count, word) => `${count} ${word}${count === 1 ? '' : 's'}`;
|
|
386
|
+
$('sub').textContent =
|
|
387
|
+
`${n(scoped.length, 'concept')} asked · ${n(answers, 'answer')} · ${scoped.filter((c) => c.mastered).length} mastered — ${where}`;
|
|
388
|
+
renderTiles(); renderChart(); renderProjects(); renderDomains();
|
|
389
|
+
renderRecent(); renderSkipped(); renderConcepts();
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
fetch('/api/state').then((r) => r.json()).then((s) => {
|
|
393
|
+
STATE = s;
|
|
394
|
+
const sel = $('proj');
|
|
395
|
+
for (const p of s.projects) {
|
|
396
|
+
const o = document.createElement('option');
|
|
397
|
+
o.value = p.repo ?? '~';
|
|
398
|
+
o.textContent = base(p.repo);
|
|
399
|
+
sel.appendChild(o);
|
|
400
|
+
}
|
|
401
|
+
sel.addEventListener('change', () => { FILTER = sel.value; renderAll(); });
|
|
402
|
+
renderAll();
|
|
403
|
+
addEventListener('resize', renderChart);
|
|
404
|
+
}).catch((e) => { $('sub').textContent = 'Could not read the database: ' + e.message; });
|
|
405
|
+
</script>
|
|
406
|
+
</body>
|
|
407
|
+
</html>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
NonStop Design System — Colors & Type
|
|
3
|
+
Brand: NonStop io · Primary: Emerald #049D66
|
|
4
|
+
Fonts: Manrope (UI/display), JetBrains Mono (code)
|
|
5
|
+
Loaded from Google Fonts CDN. See README "Visual Foundations".
|
|
6
|
+
============================================================ */
|
|
7
|
+
|
|
8
|
+
@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');
|
|
9
|
+
|
|
10
|
+
:root {
|
|
11
|
+
/* ---------- BRAND GREEN SCALE ---------- */
|
|
12
|
+
--green-50: #E6F6EF;
|
|
13
|
+
--green-100: #C3EAD8;
|
|
14
|
+
--green-200: #8FD8B6;
|
|
15
|
+
--green-300: #57C492;
|
|
16
|
+
--green-400: #1FAF74;
|
|
17
|
+
--green-500: #049D66; /* PRIMARY */
|
|
18
|
+
--green-600: #03875A;
|
|
19
|
+
--green-700: #036D49;
|
|
20
|
+
--green-800: #024E36;
|
|
21
|
+
--green-900: #013827;
|
|
22
|
+
|
|
23
|
+
/* ---------- NEUTRALS (cool slate) ---------- */
|
|
24
|
+
--neutral-0: #FFFFFF;
|
|
25
|
+
--neutral-50: #F7F9FA;
|
|
26
|
+
--neutral-100: #EEF1F3;
|
|
27
|
+
--neutral-200: #E0E5E9;
|
|
28
|
+
--neutral-300: #CAD2D8;
|
|
29
|
+
--neutral-400: #9AA6AF;
|
|
30
|
+
--neutral-500: #6B7780;
|
|
31
|
+
--neutral-600: #4D575F;
|
|
32
|
+
--neutral-700: #363F45;
|
|
33
|
+
--neutral-800: #21282D;
|
|
34
|
+
--neutral-900: #121619; /* near-black */
|
|
35
|
+
|
|
36
|
+
/* ---------- SEMANTIC / FUNCTIONAL (use sparingly) ---------- */
|
|
37
|
+
--success: #049D66; --success-bg: #E6F6EF;
|
|
38
|
+
--warning: #E8920C; --warning-bg: #FCF1DD;
|
|
39
|
+
--error: #E5484D; --error-bg: #FCE9EA;
|
|
40
|
+
--info: #2A7DE1; --info-bg: #E6F0FC;
|
|
41
|
+
|
|
42
|
+
/* ---------- SEMANTIC ROLES ---------- */
|
|
43
|
+
--brand: var(--green-500);
|
|
44
|
+
--brand-hover: var(--green-600);
|
|
45
|
+
--brand-active: var(--green-700);
|
|
46
|
+
--brand-subtle: var(--green-50);
|
|
47
|
+
--on-brand: var(--neutral-0);
|
|
48
|
+
|
|
49
|
+
--bg: var(--neutral-0); /* page background */
|
|
50
|
+
--bg-subtle: var(--neutral-50); /* app shell / sections */
|
|
51
|
+
--bg-sunken: var(--neutral-100); /* wells, code blocks */
|
|
52
|
+
--surface: var(--neutral-0); /* cards */
|
|
53
|
+
--surface-hover: var(--neutral-50);
|
|
54
|
+
|
|
55
|
+
--fg: var(--neutral-900); /* primary text */
|
|
56
|
+
--fg-muted: var(--neutral-600); /* secondary text */
|
|
57
|
+
--fg-subtle: var(--neutral-500); /* tertiary / captions */
|
|
58
|
+
--fg-faint: var(--neutral-400); /* disabled / placeholder */
|
|
59
|
+
--on-dark: var(--neutral-0);
|
|
60
|
+
--on-dark-muted: rgba(255,255,255,.68);
|
|
61
|
+
|
|
62
|
+
--border: var(--neutral-200); /* default hairline */
|
|
63
|
+
--border-strong: var(--neutral-300);
|
|
64
|
+
--border-focus: var(--green-500);
|
|
65
|
+
--ring: 0 0 0 3px rgba(4,157,102,.28); /* focus ring */
|
|
66
|
+
|
|
67
|
+
/* ---------- TYPE FAMILIES ---------- */
|
|
68
|
+
--font-sans: 'Manrope', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
69
|
+
--font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
|
|
70
|
+
|
|
71
|
+
/* ---------- TYPE SCALE (1.20 minor third) ---------- */
|
|
72
|
+
--text-xs: 12px; --lh-xs: 16px;
|
|
73
|
+
--text-sm: 14px; --lh-sm: 20px;
|
|
74
|
+
--text-base: 16px; --lh-base: 24px;
|
|
75
|
+
--text-md: 18px; --lh-md: 28px;
|
|
76
|
+
--text-lg: 20px; --lh-lg: 28px;
|
|
77
|
+
--text-xl: 24px; --lh-xl: 32px;
|
|
78
|
+
--text-2xl: 30px; --lh-2xl: 38px;
|
|
79
|
+
--text-3xl: 38px; --lh-3xl: 46px;
|
|
80
|
+
--text-4xl: 48px; --lh-4xl: 56px;
|
|
81
|
+
--text-5xl: 60px; --lh-5xl: 66px;
|
|
82
|
+
|
|
83
|
+
--weight-regular: 400;
|
|
84
|
+
--weight-medium: 500;
|
|
85
|
+
--weight-semibold:600;
|
|
86
|
+
--weight-bold: 700;
|
|
87
|
+
--weight-extra: 800;
|
|
88
|
+
|
|
89
|
+
--tracking-tight: -0.02em;
|
|
90
|
+
--tracking-snug: -0.01em;
|
|
91
|
+
--tracking-normal: 0;
|
|
92
|
+
--tracking-wide: 0.02em;
|
|
93
|
+
--tracking-caps: 0.08em;
|
|
94
|
+
|
|
95
|
+
/* ---------- SPACING (4px base) ---------- */
|
|
96
|
+
--space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px;
|
|
97
|
+
--space-5: 20px; --space-6: 24px; --space-8: 32px; --space-10: 40px;
|
|
98
|
+
--space-12: 48px; --space-16: 64px; --space-20: 80px; --space-24: 96px;
|
|
99
|
+
|
|
100
|
+
/* ---------- RADII ---------- */
|
|
101
|
+
--radius-xs: 4px;
|
|
102
|
+
--radius-sm: 6px;
|
|
103
|
+
--radius-md: 8px; /* default control radius */
|
|
104
|
+
--radius-lg: 12px; /* cards */
|
|
105
|
+
--radius-xl: 16px; /* large surfaces */
|
|
106
|
+
--radius-2xl: 24px;
|
|
107
|
+
--radius-pill: 999px;
|
|
108
|
+
|
|
109
|
+
/* ---------- SHADOWS (soft, cool-tinted) ---------- */
|
|
110
|
+
--shadow-xs: 0 1px 2px rgba(18,22,25,.06);
|
|
111
|
+
--shadow-sm: 0 1px 3px rgba(18,22,25,.08), 0 1px 2px rgba(18,22,25,.04);
|
|
112
|
+
--shadow-md: 0 4px 12px rgba(18,22,25,.08), 0 2px 4px rgba(18,22,25,.04);
|
|
113
|
+
--shadow-lg: 0 12px 28px rgba(18,22,25,.12), 0 4px 8px rgba(18,22,25,.05);
|
|
114
|
+
--shadow-brand: 0 6px 18px rgba(4,157,102,.28);
|
|
115
|
+
|
|
116
|
+
--duration-fast: 120ms;
|
|
117
|
+
--duration-base: 200ms;
|
|
118
|
+
--duration-slow: 320ms;
|
|
119
|
+
--ease: cubic-bezier(.2,.6,.2,1);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* ============================================================
|
|
123
|
+
SEMANTIC ELEMENT STYLES — apply via classes or element tags
|
|
124
|
+
============================================================ */
|
|
125
|
+
.ns-h1 { font-family:var(--font-sans); font-weight:var(--weight-extra); font-size:var(--text-4xl); line-height:var(--lh-4xl); letter-spacing:var(--tracking-tight); color:var(--fg); }
|
|
126
|
+
.ns-h2 { font-family:var(--font-sans); font-weight:var(--weight-bold); font-size:var(--text-3xl); line-height:var(--lh-3xl); letter-spacing:var(--tracking-tight); color:var(--fg); }
|
|
127
|
+
.ns-h3 { font-family:var(--font-sans); font-weight:var(--weight-bold); font-size:var(--text-2xl); line-height:var(--lh-2xl); letter-spacing:var(--tracking-snug); color:var(--fg); }
|
|
128
|
+
.ns-h4 { font-family:var(--font-sans); font-weight:var(--weight-semibold); font-size:var(--text-xl); line-height:var(--lh-xl); letter-spacing:var(--tracking-snug); color:var(--fg); }
|
|
129
|
+
.ns-h5 { font-family:var(--font-sans); font-weight:var(--weight-semibold); font-size:var(--text-md); line-height:var(--lh-md); color:var(--fg); }
|
|
130
|
+
.ns-lead { font-family:var(--font-sans); font-weight:var(--weight-regular); font-size:var(--text-lg); line-height:var(--lh-lg); color:var(--fg-muted); }
|
|
131
|
+
.ns-body { font-family:var(--font-sans); font-weight:var(--weight-regular); font-size:var(--text-base); line-height:var(--lh-base); color:var(--fg); }
|
|
132
|
+
.ns-small { font-family:var(--font-sans); font-weight:var(--weight-regular); font-size:var(--text-sm); line-height:var(--lh-sm); color:var(--fg-muted); }
|
|
133
|
+
.ns-caption { font-family:var(--font-sans); font-weight:var(--weight-medium); font-size:var(--text-xs); line-height:var(--lh-xs); color:var(--fg-subtle); }
|
|
134
|
+
.ns-overline { font-family:var(--font-sans); font-weight:var(--weight-bold); font-size:var(--text-xs); line-height:var(--lh-xs); letter-spacing:var(--tracking-caps); text-transform:uppercase; color:var(--fg-subtle); }
|
|
135
|
+
.ns-code { font-family:var(--font-mono); font-weight:var(--weight-regular); font-size:var(--text-sm); color:var(--green-700); background:var(--bg-sunken); padding:2px 6px; border-radius:var(--radius-xs); }
|
|
@@ -278,9 +278,12 @@ Every plan item carries `ask_footer`: one line naming the settings that asked th
|
|
|
278
278
|
```
|
|
279
279
|
Why is httpOnly set on the refresh cookie here but not on the access token?
|
|
280
280
|
|
|
281
|
-
concept · easy · tier 2
|
|
281
|
+
ambient · concept · easy · tier 2 mechanism · q 1/3
|
|
282
282
|
```
|
|
283
283
|
|
|
284
|
+
Mode, focus, level, what the tier is asking for, and — when the plan holds more
|
|
285
|
+
than one — which question of how many this is.
|
|
286
|
+
|
|
284
287
|
**Print it as the last line of the `question` you pass to `AskUserQuestion`**, after a blank line, exactly as given. It is the only thing on screen that explains why a question is pitched where it is — without it, a `concept`-focus question reads as vague and an `easy` question reads as shallow.
|
|
285
288
|
|
|
286
289
|
**Never pass it back in `record_attempt`.** `question` is the stem alone. The stem is what gets fingerprinted, so a footer inside it would make one question look like a new one every time the level or the focus changed, and *never the same question twice* would quietly stop being true. The server strips a trailing footer if you forget, and that is a backstop, not a licence.
|
package/dist/cli.js
CHANGED
|
@@ -11,6 +11,7 @@ import { openDb } from './db.js';
|
|
|
11
11
|
import { dbPath, eklavyaHome } from './paths.js';
|
|
12
12
|
import { loadConfig, writeConfigFile, REPO_CONFIG_FILE, DEFAULT_CONFIG } from './config.js';
|
|
13
13
|
import { levelStanding } from './store.js';
|
|
14
|
+
import { startDashboard } from './dashboard.js';
|
|
14
15
|
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
15
16
|
const USAGE = `eklavya — local learning state for agent-assisted development
|
|
16
17
|
|
|
@@ -22,6 +23,7 @@ Usage:
|
|
|
22
23
|
cadence interleaved|end,
|
|
23
24
|
difficulty auto|easy|medium|hard
|
|
24
25
|
add --topic <topic> when setting focus to "learn"
|
|
26
|
+
eklavya dashboard [--port <n>] Serve the learning dashboard on localhost
|
|
25
27
|
eklavya doctor Check that everything is wired up
|
|
26
28
|
eklavya db-path Print the database location
|
|
27
29
|
|
|
@@ -162,6 +164,20 @@ function doctor() {
|
|
|
162
164
|
if (!ok)
|
|
163
165
|
process.exit(1);
|
|
164
166
|
}
|
|
167
|
+
function dashboardCommand(argv) {
|
|
168
|
+
const i = argv.indexOf('--port');
|
|
169
|
+
const port = i === -1 ? undefined : Number(argv[i + 1]);
|
|
170
|
+
if (port !== undefined && !Number.isInteger(port)) {
|
|
171
|
+
process.stderr.write('eklavya dashboard: --port needs a number\n');
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
startDashboard(openDb(), { port }).then(({ url }) => {
|
|
175
|
+
process.stdout.write(`Eklavya dashboard on ${url}\nReading ${dbPath()} — press Ctrl+C to stop.\n`);
|
|
176
|
+
}, (err) => {
|
|
177
|
+
process.stderr.write(`eklavya dashboard: ${err.message}\n`);
|
|
178
|
+
process.exit(1);
|
|
179
|
+
});
|
|
180
|
+
}
|
|
165
181
|
function main() {
|
|
166
182
|
const [command, ...rest] = process.argv.slice(2);
|
|
167
183
|
switch (command) {
|
|
@@ -169,6 +185,8 @@ function main() {
|
|
|
169
185
|
return exportRules(rest);
|
|
170
186
|
case 'config':
|
|
171
187
|
return configCommand(rest);
|
|
188
|
+
case 'dashboard':
|
|
189
|
+
return dashboardCommand(rest);
|
|
172
190
|
case 'doctor':
|
|
173
191
|
return doctor();
|
|
174
192
|
case 'db-path':
|
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;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
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;AAC5F,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;CAkBb,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,4EAA4E;IAC5E,gEAAgE;IAChE,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IACnE,IAAI,UAAU,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK;QAAE,IAAI,CAAC,wBAAwB,CAAC,CAAC;IAChE,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;QACpE,IAAI,CAAC,0CAA0C,CAAC,CAAC;IACnD,CAAC;IACD,IAAI,GAAG,KAAK,OAAO,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAChE,IAAI,CAAC,6EAA6E,CAAC,CAAC;IACtF,CAAC;IAED,gFAAgF;IAChF,mEAAmE;IACnE,MAAM,UAAU,GAAG,GAAG,KAAK,aAAa,CAAC;IACzC,IAAI,MAAM,GAAY,KAAK,CAAC;IAC5B,IAAI,UAAU;QAAE,MAAM,GAAG,KAAK,CAAC;SAC1B,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO;QAAE,MAAM,GAAG,KAAK,KAAK,MAAM,CAAC;SACrE,IAAI,KAAK,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAAE,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE9E,MAAM,KAAK,GAA4B,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;IACzD,IAAI,KAAK,KAAK,SAAS,IAAI,GAAG,KAAK,OAAO;QAAE,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC;IAEtE,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,KAAK,CAAC,CAAC;IAC/B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,MAAM,IAAI,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED,SAAS,MAAM;IACb,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC;IACtB,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;IAC9B,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,4EAA4E;QAC5E,iEAAiE;QACjE,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,EAAE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACvE,KAAK,CAAC,IAAI,CACR,aAAa,QAAQ,CAAC,KAAK,GACzB,QAAQ,CAAC,MAAM;YACb,CAAC,CAAC,sCAAsC;YACxC,CAAC,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,uBAAuB,QAAQ,CAAC,IAAI,GAChG,EAAE,CACH,CAAC;QACF,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,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9D,KAAK,CAAC,IAAI,CAAC,aAAa,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,QAAQ,EAAE,CAAC,CAAC;IAC3D,KAAK,CAAC,IAAI,CACR,aAAa,QAAQ,CAAC,MAAM,CAAC,KAAK,GAChC,QAAQ,CAAC,MAAM,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,QAAQ,CAAC,MAAM,CAAC,WAAW,IAAI,cAAc,GAAG,CAAC,CAAC,CAAC,EAC9F,GAAG,QAAQ,EAAE,CACd,CAAC;IACF,KAAK,CAAC,IAAI,CACR,aAAa,QAAQ,CAAC,MAAM,CAAC,OAAO,GAClC,QAAQ,CAAC,MAAM,CAAC,OAAO,KAAK,aAAa;QACvC,CAAC,CAAC,gCAAgC,QAAQ,CAAC,MAAM,CAAC,+BAA+B,UAAU;QAC3F,CAAC,CAAC,yCACN,GAAG,QAAQ,EAAE,CACd,CAAC;IACF,IAAI,QAAQ,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,uBAAuB,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,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,gBAAgB,CAAC,IAAc;IACtC,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACnE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,cAAc,CAAC,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACrC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE;QACV,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wBAAwB,GAAG,aAAa,MAAM,EAAE,4BAA4B,CAAC,CAAC;IACrG,CAAC,EACD,CAAC,GAAU,EAAE,EAAE;QACb,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CACF,CAAC;AACJ,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,WAAW;YACd,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC;QAChC,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"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `eklavya dashboard` — the learning state as a local web page.
|
|
3
|
+
*
|
|
4
|
+
* The terminal report has to fit in twenty lines, so it answers "what now?".
|
|
5
|
+
* This answers "am I getting better?", which needs history, per-project
|
|
6
|
+
* comparison and the full concept list — none of which fit in a paragraph.
|
|
7
|
+
*
|
|
8
|
+
* Deliberately a static page plus one JSON endpoint: no framework, no build
|
|
9
|
+
* step, same rule the landing page follows. It binds to loopback only, which
|
|
10
|
+
* is the whole security model — the data never leaves the machine, and that
|
|
11
|
+
* is a promise the landing page makes on Eklavya's behalf.
|
|
12
|
+
*/
|
|
13
|
+
import http from 'node:http';
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { decayedScore, isDue, isKnown } from './srs.js';
|
|
18
|
+
import { GLOBAL_PROJECT } from './store.js';
|
|
19
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
/**
|
|
21
|
+
* High, unassigned, and deliberately boring to collide with.
|
|
22
|
+
*
|
|
23
|
+
* The low 5000s are where every dev server lands — Vite alone walks 5173, 5174,
|
|
24
|
+
* 5175 upward as it finds ports taken — so a default down there is a default
|
|
25
|
+
* you have to override. This sits above the registered services in /etc/services
|
|
26
|
+
* and below the 49152+ ephemeral range the OS hands out for outbound sockets,
|
|
27
|
+
* so neither end can claim it first. (1729 is the Hardy–Ramanujan number, which
|
|
28
|
+
* is as good a reason as any to remember it.)
|
|
29
|
+
*/
|
|
30
|
+
const DEFAULT_PORT = 41729;
|
|
31
|
+
/** Enough history to see a trend, short enough to stay one screen wide. */
|
|
32
|
+
const TIMELINE_DAYS = 30;
|
|
33
|
+
export function dashboardState(db) {
|
|
34
|
+
const now = new Date();
|
|
35
|
+
// One row per calendar day, split three ways. `grade >= 3` is the same pass
|
|
36
|
+
// line the level ladder uses, so the chart and the promotion agree.
|
|
37
|
+
const timeline = db
|
|
38
|
+
.prepare(`SELECT date(ts) AS day,
|
|
39
|
+
NULLIF(trim(COALESCE(repo, '')), '') AS repo,
|
|
40
|
+
sum(CASE WHEN grade >= 3 THEN 1 ELSE 0 END) AS passed,
|
|
41
|
+
sum(CASE WHEN grade < 3 AND (outcome IS NULL OR outcome = 'answered') THEN 1 ELSE 0 END) AS missed,
|
|
42
|
+
sum(CASE WHEN outcome IN ('declined','dont_know') THEN 1 ELSE 0 END) AS skipped
|
|
43
|
+
FROM attempts
|
|
44
|
+
WHERE ts >= date('now', ?)
|
|
45
|
+
GROUP BY day, repo
|
|
46
|
+
ORDER BY day`)
|
|
47
|
+
.all(`-${TIMELINE_DAYS} days`);
|
|
48
|
+
// A null repo is the pre-migration-003 bucket. It is kept, not dropped:
|
|
49
|
+
// hiding those rows would silently shrink every total on the page.
|
|
50
|
+
const projects = db
|
|
51
|
+
.prepare(`SELECT NULLIF(trim(COALESCE(a.repo, '')), '') AS repo,
|
|
52
|
+
count(*) AS answers,
|
|
53
|
+
sum(CASE WHEN a.grade >= 3 THEN 1 ELSE 0 END) AS passed,
|
|
54
|
+
sum(CASE WHEN a.outcome IN ('declined','dont_know') THEN 1 ELSE 0 END) AS skipped,
|
|
55
|
+
count(DISTINCT a.concept_id) AS concepts,
|
|
56
|
+
max(a.ts) AS last_active
|
|
57
|
+
FROM attempts a
|
|
58
|
+
GROUP BY repo
|
|
59
|
+
ORDER BY last_active DESC`)
|
|
60
|
+
.all();
|
|
61
|
+
const levels = new Map(db.prepare('SELECT repo, level, promoted_at FROM project_levels').all().map((r) => [r.repo, r]));
|
|
62
|
+
const conceptRows = db
|
|
63
|
+
.prepare(`SELECT c.slug, c.name, c.domain, c.tier,
|
|
64
|
+
m.score, m.reps, m.next_review, m.last_seen,
|
|
65
|
+
(SELECT count(*) FROM attempts a WHERE a.concept_id = c.id) AS attempts,
|
|
66
|
+
(SELECT a.grade FROM attempts a WHERE a.concept_id = c.id ORDER BY a.id DESC LIMIT 1) AS last_grade,
|
|
67
|
+
(SELECT sc.context FROM session_concepts sc
|
|
68
|
+
WHERE sc.concept_id = c.id AND sc.context IS NOT NULL
|
|
69
|
+
ORDER BY sc.ts DESC LIMIT 1) AS last_context,
|
|
70
|
+
(SELECT a.repo FROM attempts a
|
|
71
|
+
WHERE a.concept_id = c.id AND a.repo IS NOT NULL AND trim(a.repo) <> ''
|
|
72
|
+
ORDER BY a.id DESC LIMIT 1) AS last_repo
|
|
73
|
+
FROM concepts c
|
|
74
|
+
LEFT JOIN mastery m ON m.concept_id = c.id`)
|
|
75
|
+
.all();
|
|
76
|
+
const domains = new Map();
|
|
77
|
+
const concepts = [];
|
|
78
|
+
for (const row of conceptRows) {
|
|
79
|
+
const bucket = domains.get(row.domain) ?? { domain: row.domain, mastered: 0, learning: 0, unseen: 0 };
|
|
80
|
+
domains.set(row.domain, bucket);
|
|
81
|
+
if (row.attempts === 0) {
|
|
82
|
+
bucket.unseen += 1;
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// Read-time decay only, exactly as the profile computes it — two surfaces
|
|
86
|
+
// disagreeing about the same score is worse than either being wrong.
|
|
87
|
+
const score = decayedScore(row.score ?? 0, row.next_review, now);
|
|
88
|
+
const mastered = isKnown({ score, reps: row.reps ?? 0 });
|
|
89
|
+
if (mastered)
|
|
90
|
+
bucket.mastered += 1;
|
|
91
|
+
else
|
|
92
|
+
bucket.learning += 1;
|
|
93
|
+
concepts.push({
|
|
94
|
+
slug: row.slug,
|
|
95
|
+
name: row.name,
|
|
96
|
+
domain: row.domain,
|
|
97
|
+
tier: row.tier,
|
|
98
|
+
score: Number(score.toFixed(2)),
|
|
99
|
+
reps: row.reps ?? 0,
|
|
100
|
+
attempts: row.attempts,
|
|
101
|
+
last_grade: row.last_grade,
|
|
102
|
+
mastered,
|
|
103
|
+
due: isDue(row.next_review, now),
|
|
104
|
+
next_review: row.next_review,
|
|
105
|
+
last_seen: row.last_seen,
|
|
106
|
+
context: row.last_context,
|
|
107
|
+
repo: row.last_repo,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
concepts.sort((a, b) => a.score - b.score);
|
|
111
|
+
const skipped = db
|
|
112
|
+
.prepare(`SELECT c.slug AS slug, c.name AS name, c.domain AS domain,
|
|
113
|
+
a.outcome AS outcome, a.repo AS repo, a.ts AS ts, a.question AS question
|
|
114
|
+
FROM attempts a JOIN concepts c ON c.id = a.concept_id
|
|
115
|
+
WHERE a.outcome IN ('declined','dont_know')
|
|
116
|
+
ORDER BY a.ts DESC`)
|
|
117
|
+
.all();
|
|
118
|
+
const recent = db
|
|
119
|
+
.prepare(`SELECT c.slug AS slug, c.domain AS domain, sc.context AS context, sc.ts AS ts, g.repo AS repo
|
|
120
|
+
FROM session_concepts sc
|
|
121
|
+
JOIN concepts c ON c.id = sc.concept_id
|
|
122
|
+
LEFT JOIN gates g ON g.session_id = sc.session_id
|
|
123
|
+
WHERE sc.context IS NOT NULL AND trim(sc.context) <> ''
|
|
124
|
+
ORDER BY sc.ts DESC
|
|
125
|
+
LIMIT 40`)
|
|
126
|
+
.all();
|
|
127
|
+
const totals = timeline.reduce((acc, d) => ({
|
|
128
|
+
passed: acc.passed + d.passed,
|
|
129
|
+
missed: acc.missed + d.missed,
|
|
130
|
+
skipped: acc.skipped + d.skipped,
|
|
131
|
+
}), { passed: 0, missed: 0, skipped: 0 });
|
|
132
|
+
const allTime = db
|
|
133
|
+
.prepare(`SELECT count(*) AS answers,
|
|
134
|
+
sum(CASE WHEN grade >= 3 THEN 1 ELSE 0 END) AS passed,
|
|
135
|
+
sum(CASE WHEN outcome IN ('declined','dont_know') THEN 1 ELSE 0 END) AS skipped
|
|
136
|
+
FROM attempts`)
|
|
137
|
+
.get();
|
|
138
|
+
return {
|
|
139
|
+
generated_at: now.toISOString(),
|
|
140
|
+
timeline_days: TIMELINE_DAYS,
|
|
141
|
+
totals: {
|
|
142
|
+
answers: allTime.answers,
|
|
143
|
+
passed: allTime.passed ?? 0,
|
|
144
|
+
skipped: allTime.skipped ?? 0,
|
|
145
|
+
mastered: concepts.filter((c) => c.mastered).length,
|
|
146
|
+
due: concepts.filter((c) => c.due).length,
|
|
147
|
+
touched: concepts.length,
|
|
148
|
+
catalogue: conceptRows.length,
|
|
149
|
+
window: totals,
|
|
150
|
+
},
|
|
151
|
+
timeline,
|
|
152
|
+
projects: projects.map((p) => ({
|
|
153
|
+
...p,
|
|
154
|
+
level: levels.get(p.repo ?? GLOBAL_PROJECT)?.level ?? 'easy',
|
|
155
|
+
promoted_at: levels.get(p.repo ?? GLOBAL_PROJECT)?.promoted_at ?? null,
|
|
156
|
+
})),
|
|
157
|
+
domains: [...domains.values()].sort((a, b) => b.mastered + b.learning - (a.mastered + a.learning)),
|
|
158
|
+
concepts,
|
|
159
|
+
skipped,
|
|
160
|
+
recent,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function send(res, status, type, body) {
|
|
164
|
+
res.writeHead(status, {
|
|
165
|
+
'content-type': type,
|
|
166
|
+
// A dashboard read from a stale cache is a dashboard that lies about
|
|
167
|
+
// progress made ten seconds ago, which is the one thing it is for.
|
|
168
|
+
'cache-control': 'no-store',
|
|
169
|
+
});
|
|
170
|
+
res.end(body);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Starts the server and resolves with the URL it actually bound to. The
|
|
174
|
+
* requested port may be taken by a second dashboard or an unrelated dev
|
|
175
|
+
* server; falling back to an ephemeral port beats failing with EADDRINUSE
|
|
176
|
+
* when the caller does not care which port it gets.
|
|
177
|
+
*/
|
|
178
|
+
export function startDashboard(db, opts = {}) {
|
|
179
|
+
const host = opts.host ?? '127.0.0.1';
|
|
180
|
+
const wanted = opts.port ?? DEFAULT_PORT;
|
|
181
|
+
const assets = path.join(moduleDir, 'assets');
|
|
182
|
+
const server = http.createServer((req, res) => {
|
|
183
|
+
const url = new URL(req.url ?? '/', `http://${host}`);
|
|
184
|
+
try {
|
|
185
|
+
if (url.pathname === '/api/state') {
|
|
186
|
+
return send(res, 200, 'application/json', JSON.stringify(dashboardState(db)));
|
|
187
|
+
}
|
|
188
|
+
if (url.pathname === '/tokens.css') {
|
|
189
|
+
return send(res, 200, 'text/css', fs.readFileSync(path.join(assets, 'tokens.css')));
|
|
190
|
+
}
|
|
191
|
+
if (url.pathname === '/' || url.pathname === '/index.html') {
|
|
192
|
+
return send(res, 200, 'text/html; charset=utf-8', fs.readFileSync(path.join(assets, 'dashboard.html')));
|
|
193
|
+
}
|
|
194
|
+
return send(res, 404, 'text/plain', 'not found');
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
return send(res, 500, 'text/plain', err instanceof Error ? err.message : 'error');
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
server.once('error', (err) => {
|
|
202
|
+
if (err.code !== 'EADDRINUSE' || opts.port !== undefined)
|
|
203
|
+
return reject(err);
|
|
204
|
+
server.listen(0, host);
|
|
205
|
+
});
|
|
206
|
+
server.on('listening', () => {
|
|
207
|
+
const addr = server.address();
|
|
208
|
+
const port = typeof addr === 'object' && addr ? addr.port : wanted;
|
|
209
|
+
resolve({ url: `http://${host}:${port}`, close: () => server.close() });
|
|
210
|
+
});
|
|
211
|
+
server.listen(wanted, host);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=dashboard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ const WEAK_THRESHOLD = 0.5;
|
|
|
10
10
|
export const getLearnerProfile = {
|
|
11
11
|
name: 'get_learner_profile',
|
|
12
12
|
title: 'Get learner profile',
|
|
13
|
-
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, the tier to pitch at, and this project\'s difficulty level with the progress toward the next one. Every tier here is already clamped to that level.',
|
|
13
|
+
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, the tier to pitch at, and this project\'s difficulty level with the progress toward the next one. Every tier here is already clamped to that level. Also returns the three things a progress report needs and mastery counts cannot give: `projects` (per-repo answered/passed, so a report can say *which* codebase), `recent_concepts` (what was logged, with the context line naming the real code it came from) and `skipped` (declined or blanked, the actionable backlog).',
|
|
14
14
|
inputSchema: {
|
|
15
15
|
domain: z.string().optional().describe('Restrict to one domain, e.g. "web-auth".'),
|
|
16
16
|
cwd: z.string().optional().describe(CWD_HINT),
|
|
@@ -74,6 +74,41 @@ export const getLearnerProfile = {
|
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
|
+
const domainFilter = args.domain ? 'AND c.domain = ?' : '';
|
|
78
|
+
const domainArg = args.domain ? [args.domain] : [];
|
|
79
|
+
// Three things mastery counts cannot answer, and a progress report must:
|
|
80
|
+
// which project this happened on, what was actually learned there, and
|
|
81
|
+
// what was ducked. All three are already in the schema; nothing read them.
|
|
82
|
+
const projects = db
|
|
83
|
+
.prepare(`SELECT NULLIF(trim(COALESCE(a.repo, '')), '') AS repo, count(*) AS answers,
|
|
84
|
+
sum(CASE WHEN a.grade >= 3 THEN 1 ELSE 0 END) AS passed,
|
|
85
|
+
max(a.ts) AS last_active
|
|
86
|
+
FROM attempts a JOIN concepts c ON c.id = a.concept_id
|
|
87
|
+
WHERE 1 = 1 ${domainFilter}
|
|
88
|
+
GROUP BY repo
|
|
89
|
+
ORDER BY last_active DESC
|
|
90
|
+
LIMIT ?`)
|
|
91
|
+
.all(...domainArg, LIST_CAP);
|
|
92
|
+
// `session_concepts` has no repo of its own; the session's gate row carries
|
|
93
|
+
// it. LEFT JOIN because a session that never opened a gate still logged work.
|
|
94
|
+
const recent = db
|
|
95
|
+
.prepare(`SELECT c.slug AS slug, sc.context AS context, sc.ts AS ts, g.repo AS repo
|
|
96
|
+
FROM session_concepts sc
|
|
97
|
+
JOIN concepts c ON c.id = sc.concept_id
|
|
98
|
+
LEFT JOIN gates g ON g.session_id = sc.session_id
|
|
99
|
+
WHERE sc.context IS NOT NULL AND trim(sc.context) <> '' ${domainFilter}
|
|
100
|
+
ORDER BY sc.ts DESC
|
|
101
|
+
LIMIT ?`)
|
|
102
|
+
.all(...domainArg, LIST_CAP);
|
|
103
|
+
// A NULL outcome is a row written before migration 004, not a skip. `IN`
|
|
104
|
+
// excludes it: counting those as ducked would invent a backlog.
|
|
105
|
+
const skipped = db
|
|
106
|
+
.prepare(`SELECT c.slug AS slug, a.outcome AS outcome, a.repo AS repo, a.ts AS ts
|
|
107
|
+
FROM attempts a JOIN concepts c ON c.id = a.concept_id
|
|
108
|
+
WHERE a.outcome IN ('declined','dont_know') ${domainFilter}
|
|
109
|
+
ORDER BY a.ts DESC
|
|
110
|
+
LIMIT ?`)
|
|
111
|
+
.all(...domainArg, LIST_CAP);
|
|
77
112
|
weak.sort((a, b) => a.score - b.score);
|
|
78
113
|
due.sort((a, b) => b.tier - a.tier);
|
|
79
114
|
known.sort((a, b) => b.score - a.score);
|
|
@@ -84,6 +119,9 @@ export const getLearnerProfile = {
|
|
|
84
119
|
known_total: known.length,
|
|
85
120
|
weak: weak.slice(0, LIST_CAP).map((w) => w.slug),
|
|
86
121
|
due_for_review: due.slice(0, LIST_CAP),
|
|
122
|
+
projects,
|
|
123
|
+
recent_concepts: recent,
|
|
124
|
+
skipped,
|
|
87
125
|
suggested_tier: clampToLevel(suggestedTier(knownTiers), standing.level),
|
|
88
126
|
level: {
|
|
89
127
|
level: standing.level,
|
|
@@ -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,YAAY,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACrG,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAEpD,MAAM,QAAQ,GAAG,CAAC,CAAC;AACnB,2FAA2F;AAC3F,MAAM,SAAS,GAAG,EAAE,CAAC;AACrB,MAAM,cAAc,GAAG,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"get_learner_profile.js","sourceRoot":"","sources":["../../src/tools/get_learner_profile.ts"],"names":[],"mappings":"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"}
|
|
@@ -331,6 +331,21 @@ export const getSessionQuizPlan = {
|
|
|
331
331
|
}
|
|
332
332
|
return a.tier_to_ask - b.tier_to_ask;
|
|
333
333
|
});
|
|
334
|
+
// Numbered after the sort, so `q 2/3` is the order they will actually be
|
|
335
|
+
// asked in. Only when there is more than one -- `q 1/1` is noise.
|
|
336
|
+
if (picked.length > 1) {
|
|
337
|
+
picked.forEach((item, i) => {
|
|
338
|
+
const numbered = askFooter({
|
|
339
|
+
config,
|
|
340
|
+
level: standing.level,
|
|
341
|
+
pinned: standing.pinned,
|
|
342
|
+
tier: item.tier_to_ask,
|
|
343
|
+
position: { index: i + 1, total: picked.length },
|
|
344
|
+
});
|
|
345
|
+
if (numbered)
|
|
346
|
+
item.ask_footer = numbered;
|
|
347
|
+
});
|
|
348
|
+
}
|
|
334
349
|
if (picked.length === 0) {
|
|
335
350
|
// Distinguish "nothing left to ask" from "nothing to ask about" — they
|
|
336
351
|
// need different things said to the developer.
|
|
@@ -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,EAAc,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAc,MAAM,WAAW,CAAC;AAClG,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,iBAAiB,EACjB,OAAO,EACP,SAAS,EACT,YAAY,EACZ,WAAW,EACX,aAAa,EACb,aAAa,EACb,UAAU,EACV,eAAe,EACf,eAAe,EACf,YAAY,EACZ,aAAa,GAId,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAgB,MAAM,YAAY,CAAC;AAiElE;;;GAGG;AACH,MAAM,OAAO,GAA0B;IACrC,OAAO,EACL,iHAAiH;IACnH,OAAO,EACL,+TAA+T;IACjU,KAAK,EACH,qRAAqR;CACxR,CAAC;AAEF;;;;GAIG;AACH,MAAM,aAAa,GAA0B;IAC3C,IAAI,EACF,+SAA+S;IACjT,MAAM,EACJ,0JAA0J;IAC5J,IAAI,EACF,kMAAkM;CACrM,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,SAAS,YAAY,CAAC,GAAkB,EAAE,GAAS;IACjD,IAAI,CAAC,GAAG;QAAE,OAAO,MAAM,CAAC,iBAAiB,CAAC;IAC1C,2EAA2E;IAC3E,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5E,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,MAAM,CAAC,iBAAiB,CAAC;IACzD,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAY;IACzC,IAAI,EAAE,uBAAuB;IAC7B,KAAK,EAAE,uBAAuB;IAC9B,WAAW,EACT,kkDAAkkD;IACpkD,WAAW,EAAE;QACX,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;QACxD,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC7C,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sEAAsE,CAAC;QAChI,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,qHAAqH,CAAC;QAClI,KAAK,EAAE,CAAC;aACL,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,QAAQ,EAAE;aACV,QAAQ,CAAC,mGAAmG,CAAC;QAChH,eAAe,EAAE,CAAC;aACf,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,qHAAqH,CAAC;QAClI,KAAK,EAAE,CAAC;aACL,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;aACrC,QAAQ,EAAE;aACV,QAAQ,CAAC,0EAA0E,CAAC;KACxF;IACD,OAAO,EAAE,CACP,IAQC,EACD,EAAE,EAAE,EAAE,EACN,EAAE;QACF,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,SAAS,GAAG,gBAAgB,CAAC,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,MAAM,CAAC,sBAAsB,CAAC;QACtD,MAAM,KAAK,GAAU,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAC;QAChD,yEAAyE;QACzE,qEAAqE;QACrE,+DAA+D;QAC/D,MAAM,QAAQ,GAAG,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAErD,qEAAqE;QACrE,4EAA4E;QAC5E,2EAA2E;QAC3E,4DAA4D;QAC5D,IAAI,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;QAC5B,IAAI,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC;QAC1B,IAAI,eAAe,GAAG,KAAK,CAAC;QAC5B,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAEpF,IAAI,CAAC,aAAa,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;YACxC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;gBACxB,OAAO;oBACL,UAAU,EAAE,SAAS;oBACrB,gBAAgB,EAAE,CAAC;oBACnB,QAAQ,EAAE,EAAE;oBACZ,KAAK;oBACL,MAAM,EAAE,UAAU;oBAClB,MAAM,EAAE,uGAAuG;iBAChH,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,GAAG,YAAY,CAAC,EAAE,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;YACnD,IAAI,KAAK,CAAC,MAAM;gBAAE,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC;iBACtC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC;;gBACnD,eAAe,GAAG,IAAI,CAAC;QAC9B,CAAC;QAED,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAE1E,IAAI,MAAM,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YAC1B,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,gBAAgB,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;QAC1F,CAAC;QAED,4EAA4E;QAC5E,6EAA6E;QAC7E,kEAAkE;QAClE,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YACvD,MAAM,KAAK,GAAG,YAAY,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC,CAAC;YAC9D,IAAI,KAAK,GAAG,MAAM,CAAC,2BAA2B,EAAE,CAAC;gBAC/C,OAAO;oBACL,UAAU,EAAE,SAAS;oBACrB,gBAAgB,EAAE,CAAC;oBACnB,QAAQ,EAAE,EAAE;oBACZ,MAAM,EAAE,UAAU;oBAClB,iBAAiB,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,2BAA2B,GAAG,KAAK,CAAC;iBACzE,CAAC;YACJ,CAAC;QACH,CAAC;QAED,2EAA2E;QAC3E,+DAA+D;QAC/D,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO;gBACL,UAAU,EAAE,SAAS;gBACrB,gBAAgB,EAAE,CAAC;gBACnB,QAAQ,EAAE,EAAE;gBACZ,KAAK;gBACL,KAAK,EAAE,MAAM,CAAC,WAAW;gBACzB,MAAM,EAAE,eAAe;gBACvB,MAAM,EAAE,iCAAiC,MAAM,CAAC,WAAW,mHAAmH;aAC/K,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAe,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,2EAA2E;QAC3E,2EAA2E;QAC3E,MAAM,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;QACjD,KAAK,MAAM,CAAC,IAAI,eAAe,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,CAAC,OAAO;gBAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QACvD,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;QAClC,6EAA6E;QAC7E,yEAAyE;QACzE,MAAM,YAAY,GAAG,mBAAmB,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;QACxD,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,MAAM,GAAG,GAAG,CACV,OAAmB,EACnB,OAAsB,EACtB,MAA0B;QAC1B,uEAAuE;QACvE,qEAAqE;QACrE,gEAAgE;QAChE,OAA4B,EAAE,EACxB,EAAE;YACR,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG;gBAAE,OAAO;YAC3D,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC;gBAChD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBACvB,YAAY,IAAI,CAAC,CAAC;gBAClB,OAAO;YACT,CAAC;YAED,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;YACxD,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;YACzC,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;YAE7D,MAAM,IAAI,GAAG,YAAY,CACvB,aAAa,CAAC;gBACZ,WAAW,EAAE,OAAO,CAAC,IAAI;gBACzB,cAAc,EAAE,IAAI,EAAE,UAAU,IAAI,IAAI;gBACxC,SAAS,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI;gBAC9B,KAAK;aACN,CAAC,EACF,QAAQ,CAAC,KAAK,CACf,CAAC;YACF,4EAA4E;YAC5E,kEAAkE;YAClE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7E,MAAM,MAAM,GAAG,SAAS,CAAC;gBACvB,MAAM;gBACN,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,IAAI,EAAE,SAAS;aAChB,CAAC,CAAC;YAEH,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACvB,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,WAAW,EAAE,SAAS;gBACtB,OAAO;gBACP,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,yEAAyE;gBACzE,uEAAuE;gBACvE,kDAAkD;gBAClD,GAAG,CAAC,KAAK,KAAK,OAAO,IAAI,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;oBACvD,CAAC,CAAC,EAAE,cAAc,EAAE,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAE,EAAE;oBACvD,CAAC,CAAC,EAAE,CAAC;gBACP,UAAU,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI;gBAC/B,YAAY,EAAE,KAAK;gBACnB,cAAc,EAAE,aAAa,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC;gBAC7C,aAAa,EAAE,YAAY,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC;gBAChD,aAAa,EAAE,KAAK;gBACpB,eAAe,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC;gBAC3D,MAAM;aACP,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,SAAS,EAAE,CAAC;YACd,0EAA0E;YAC1E,sEAAsE;YACtE,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAc,EAAE,CAAC;YAC7B,IAAI,SAAS,EAAE,CAAC;gBACd,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACzB,CAAC;YACD,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,IAAI,CAAC,cAAc,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBACjE,MAAM,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,CAAC;YAC3B,CAAC;YAED,MAAM,IAAI,GAAG,EAAE;iBACZ,OAAO,CACN;;qBAEW,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC;4CACG,CACnC;iBACA,GAAG,CAAC,GAAG,MAAM,CAAiB,CAAC;YAElC,uEAAuE;YACvE,uEAAuE;YACvE,MAAM,UAAU,GAAG,IAAI;iBACpB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACT,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;gBACxD,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,CAAC;YAC/F,CAAC,CAAC;iBACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC;iBAChC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;gBACb,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG;oBAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC3C,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;oBAAE,OAAO,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;gBAClD,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YAC7B,CAAC,CAAC,CAAC;YAEL,wEAAwE;YACxE,sEAAsE;YACtE,sBAAsB;YACtB,MAAM,WAAW,GAAG,CAAC,aAAa,IAAI,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC;YAClF,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;gBAC9B,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,WAAW,CAAC,CAAC;YACpE,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,eAAe,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YAC/C,KAAK,MAAM,CAAC,IAAI,OAAO;gBAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAE/C,sEAAsE;YACtE,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC/B,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;gBACxD,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;oBAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YACzE,CAAC;YAED,4DAA4D;YAC5D,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC/B,IAAI,KAAK,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC;oBAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;YACjE,CAAC;YAED,yEAAyE;YACzE,sEAAsE;YACtE,uEAAuE;YACvE,2CAA2C;YAC3C,EAAE;YACF,2EAA2E;YAC3E,+CAA+C;YAC/C,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;gBAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC5C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;gBAEpC,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,EAAE,EAAE,UAAU,CAAC,EAAE,CAAC;oBAC1C,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC/B,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;wBACjF,4DAA4D;wBAC5D,+DAA+D;wBAC/D,+DAA+D;wBAC/D,mBAAmB;wBACnB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;gBAED,KAAK,MAAM,CAAC,IAAI,cAAc,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC;oBAC1D,IAAI,MAAM,CAAC,MAAM,IAAI,GAAG;wBAAE,MAAM;oBAChC,MAAM,CAAC,GAAG,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC/B,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;wBACjF,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,kBAAkB,CAAC,CAAC;oBACnC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,2EAA2E;YAC3E,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBAC5C,MAAM,YAAY,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC3D,MAAM,IAAI,GAAG,EAAE;qBACZ,OAAO,CACN;;kCAEsB,YAAY;wCACN,CAC7B;qBACA,GAAG,CAAC,GAAG,OAAO,EAAE,GAAG,CAAC,WAAW,EAAE,CAAiB,CAAC;gBACtD,KAAK,MAAM,CAAC,IAAI,IAAI;oBAAE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QAED,4EAA4E;QAC5E,6EAA6E;QAC7E,6EAA6E;QAC7E,4EAA4E;QAC5E,4EAA4E;QAC5E,mDAAmD;QACnD,EAAE;QACF,2EAA2E;QAC3E,0EAA0E;QAC1E,WAAW;QACX,IAAI,CAAC,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACpE,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,EAAE,SAAS,CAAC,CAAC;YACpC,IAAI,IAAI,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;gBAC9C,oEAAoE;gBACpE,wEAAwE;gBACxE,kEAAkE;gBAClE,0EAA0E;gBAC1E,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,KAAK,MAAM,CAAC,IAAI,iBAAiB,CAAC,EAAE,EAAE,SAAS,CAAC,EAAE,CAAC;oBACjD,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBACnD,CAAC;YACH,CAAC;QACH,CAAC;QAED,sEAAsE;QACtE,6CAA6C;QAC7C,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACnB,IAAI,CAAC,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC;gBACtD,OAAO,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC;YACzD,CAAC;YACD,OAAO,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,uEAAuE;YACvE,+CAA+C;YAC/C,OAAO,YAAY,GAAG,CAAC;gBACrB,CAAC,CAAC;oBACE,UAAU,EAAE,SAAS;oBACrB,gBAAgB,EAAE,CAAC;oBACnB,QAAQ,EAAE,EAAE;oBACZ,KAAK;oBACL,MAAM,EAAE,iBAAiB;oBACzB,MAAM,EAAE,GAAG,YAAY,uDAAuD;iBAC/E;gBACH,CAAC,CAAC;oBACE,UAAU,EAAE,SAAS;oBACrB,gBAAgB,EAAE,CAAC;oBACnB,QAAQ,EAAE,EAAE;oBACZ,KAAK;oBACL,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,gBAAgB;iBACvD,CAAC;QACR,CAAC;QAED,OAAO;YACL,UAAU,EAAE,SAAS;YACrB,gBAAgB,EAAE,MAAM,CAAC,MAAM;YAC/B,KAAK;YACL,wEAAwE;YACxE,gEAAgE;YAChE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC;YACvB,GAAG,CAAC,KAAK,KAAK,OAAO,IAAI,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACjF,KAAK,EAAE,QAAQ,CAAC,KAAK;YACrB,aAAa,EAAE,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC5C,cAAc,EAAE;gBACd,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM;gBAC9B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,OAAO;gBAC/B,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBAClC,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBACzC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;gBAC3B,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,QAAQ;gBACtC,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC7C;YACD,QAAQ,EAAE,MAAM;SACjB,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"get_session_quiz_plan.js","sourceRoot":"","sources":["../../src/tools/get_session_quiz_plan.ts"],"names":[],"mappings":"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"}
|