eklavya 1.76.0 → 1.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ npx eklavya --version
|
|
|
122
122
|
|
|
123
123
|
The [CLI reference](https://eklavya-run.web.app/docs/cli/) lists all commands and
|
|
124
124
|
flags. `feedback generate` reviews one of your earlier prompts, using what your later prompts in that session had to add, when `feedback.enabled`,
|
|
125
|
-
memory and `providers.observer` are set. Once a day, after your first answer, the Learning dashboard opens one card on arrival (a milestone, a welcome back, the most overdue concept and so on), chosen by the engine in `assets/daily-card.cjs`; the Daily card switch on Settings, Companion, turns it off. The dashboard reads the database (its Concepts page shows each concept's tags and filters by one with `?tag=`) and has five guarded writes: a setting
|
|
125
|
+
memory and `providers.observer` are set. Once a day, after your first answer, the Learning dashboard opens one card on arrival (a milestone, a welcome back, the most overdue concept and so on), chosen by the engine in `assets/daily-card.cjs`; the Daily card switch on Settings, Companion, turns it off. Dashboard counts of 1,000 or more read short (1K, 1.2K, 1M). The dashboard reads the database (its Concepts page shows each concept's tags and filters by one with `?tag=`) and has five guarded writes: a setting
|
|
126
126
|
change, a correction of a missed answer (which can also complete a level), and acknowledging, deleting or counting the opening of a
|
|
127
127
|
feedback item (`POST /api/feedback/acknowledge`, `/delete`, `/opened`; the reads are `GET /api/feedback` and `/api/feedback/list`). An open page listens to
|
|
128
128
|
`GET /api/events`, a stream of the change cursor (a counter that moves on every
|
|
@@ -739,9 +739,9 @@
|
|
|
739
739
|
@keyframes toast-in { from { opacity:0; transform:translateY(10px); } }
|
|
740
740
|
/* The daily card (see DAILY): one native dialog, square, hairline, the archer on top. */
|
|
741
741
|
dialog.daily { width:min(440px, calc(100vw - 32px)); max-height:calc(100vh - 32px); max-height:calc(100dvh - 32px); margin:auto; padding:0;
|
|
742
|
-
border:1px solid var(--line-2); border-radius:0; background:var(--panel); color:var(--ink); box-shadow:var(--
|
|
742
|
+
border:1px solid var(--line-2); border-radius:0; background:var(--panel); color:var(--ink); box-shadow:0 0 0 1px var(--line-2), 0 24px 80px rgba(0,0,0,.6);
|
|
743
743
|
overflow-x:hidden; overflow-y:auto; }
|
|
744
|
-
dialog.daily::backdrop { background:color-mix(in srgb, var(--
|
|
744
|
+
dialog.daily::backdrop { background:color-mix(in srgb, var(--ink) 55%, transparent); backdrop-filter:blur(10px) saturate(.8); }
|
|
745
745
|
dialog.daily[open] { animation:daily-in var(--duration-slow) var(--ease); }
|
|
746
746
|
@keyframes daily-in { from { opacity:0; transform:translateY(16px); } }
|
|
747
747
|
.daily__x { position:absolute; top:var(--space-2); right:var(--space-2); width:32px; height:32px; display:grid; place-items:center;
|
|
@@ -761,8 +761,8 @@
|
|
|
761
761
|
.daily__btn--quiet { border-color:transparent; background:transparent; color:var(--dim); }
|
|
762
762
|
.say { position:relative; background:var(--bg); border:1.5px solid var(--ink); padding:10px 14px; max-width:260px; font:600 13.5px/1.4 var(--font-body);
|
|
763
763
|
margin-bottom:26px; }
|
|
764
|
-
.say::after { content:""; position:absolute;
|
|
765
|
-
border-
|
|
764
|
+
.say::after { content:""; position:absolute; left:-9px; bottom:14px; width:14px; height:14px; background:var(--bg);
|
|
765
|
+
border-left:1.5px solid var(--ink); border-bottom:1.5px solid var(--ink); transform:rotate(45deg); }
|
|
766
766
|
.daily__row { display:flex; gap:var(--space-4); align-items:center; }
|
|
767
767
|
.daily__big { font:900 56px/.9 var(--font-disp); letter-spacing:-.05em; font-variant-numeric:tabular-nums; }
|
|
768
768
|
.daily__lbl { font:500 10.5px/1 var(--font-mono); letter-spacing:.18em; text-transform:uppercase; color:var(--faint); }
|
|
@@ -798,6 +798,8 @@
|
|
|
798
798
|
@keyframes confetti { 0% { opacity:1; transform:translateY(0) rotate(0); } 100% { opacity:0; transform:translateY(480px) rotate(540deg); } }
|
|
799
799
|
.streak__talk { display:flex; align-items:flex-end; gap:var(--space-1); max-width:100%; }
|
|
800
800
|
.streak__talk .say { margin-bottom:30px; }
|
|
801
|
+
/* Here the archer stands to the right of the bubble, so its tail points right. */
|
|
802
|
+
.streak__talk .say::after { left:auto; right:-9px; border-left:0; border-bottom:0; border-right:1.5px solid var(--ink); border-top:1.5px solid var(--ink); }
|
|
801
803
|
@media (prefers-reduced-motion:reduce) { dialog.daily[open], .daily__flame.is-live { animation:none; }
|
|
802
804
|
.daily__ring .f, .daily__bar > b, .daily__bars i { transition:none; } .daily__confetti { display:none; } }
|
|
803
805
|
dialog.dlg { width:min(460px, calc(100vw - 32px)); margin:auto; padding:0; border:1px solid var(--line-2); border-radius:0;
|
|
@@ -1386,7 +1388,10 @@ const stamp = (ts) => {
|
|
|
1386
1388
|
return d.toLocaleDateString(undefined, { month:'short', day:'numeric' })
|
|
1387
1389
|
+ ', ' + d.toLocaleTimeString(undefined, { hour:'2-digit', minute:'2-digit' });
|
|
1388
1390
|
};
|
|
1389
|
-
|
|
1391
|
+
/** Counts of 1,000 and up read short: 1K, 1.2K, 1M. Below that, the number as it is. Strings pass through. */
|
|
1392
|
+
const COMPACT = new Intl.NumberFormat('en', { notation:'compact', maximumFractionDigits:1 });
|
|
1393
|
+
const fmtN = (n) => (typeof n === 'number' && Math.abs(n) >= 1000 ? COMPACT.format(n) : n);
|
|
1394
|
+
const plural = (n, w) => `${fmtN(n)} ${w}${n === 1 ? '' : 's'}`;
|
|
1390
1395
|
|
|
1391
1396
|
const TIER = { 1:'recall', 2:'mechanism', 3:'judgement', 4:'failure modes', 5:'design' };
|
|
1392
1397
|
const tierLabel = (t) => `T${t}${TIER[t] ? ' ' + TIER[t] : ''}`;
|
|
@@ -1717,7 +1722,7 @@ const statePill = (c) =>
|
|
|
1717
1722
|
function tiles(items) {
|
|
1718
1723
|
return `<div class="stats">` + items.map(([k, v, n, kind, go]) =>
|
|
1719
1724
|
`<div class="tile${kind ? ' is-' + kind : ''}"${go ? ` data-go="${esc(go)}" tabindex="0" role="link"` : ''}>`
|
|
1720
|
-
+ `<b>${esc(k)}</b><strong>${esc(v)}</strong><span>${esc(n)}</span></div>`
|
|
1725
|
+
+ `<b>${esc(k)}</b><strong>${esc(fmtN(v))}</strong><span>${esc(n)}</span></div>`
|
|
1721
1726
|
).join('') + `</div>`;
|
|
1722
1727
|
}
|
|
1723
1728
|
|
|
@@ -2654,8 +2659,8 @@ function viewLearningDashboard() {
|
|
|
2654
2659
|
answered moves a score.`),
|
|
2655
2660
|
|
|
2656
2661
|
tiles([
|
|
2657
|
-
['Accuracy', answered ? pct(passed, answered) + '%' : '—', answered ? `${passed} right of ${answered}` : 'No assessments yet', answered && pct(passed, answered) >= 70 ? 'good' : '', LH('sessions')],
|
|
2658
|
-
['Mastered', mastered.length, `of ${seen.length} asked`, mastered.length ? 'good' : '', LH('concepts', 'mastered')],
|
|
2662
|
+
['Accuracy', answered ? pct(passed, answered) + '%' : '—', answered ? `${fmtN(passed)} right of ${fmtN(answered)}` : 'No assessments yet', answered && pct(passed, answered) >= 70 ? 'good' : '', LH('sessions')],
|
|
2663
|
+
['Mastered', mastered.length, `of ${fmtN(seen.length)} asked`, mastered.length ? 'good' : '', LH('concepts', 'mastered')],
|
|
2659
2664
|
['Due now', due.length, due.length ? 'ready for review' : 'nothing waiting', due.length ? 'warn' : '', LH('review')],
|
|
2660
2665
|
toCorrectTile(),
|
|
2661
2666
|
]),
|
|
@@ -3418,10 +3423,10 @@ function memTiles() {
|
|
|
3418
3423
|
const { scoped, events, pending, entries, sessions } = memCounts();
|
|
3419
3424
|
const everywhere = scoped ? 'all projects · ' : '';
|
|
3420
3425
|
return tiles([
|
|
3421
|
-
['Observations', entries, scoped ? 'live in this project' : `${M.indexed} indexed`, '', MH('timeline')],
|
|
3426
|
+
['Observations', entries, scoped ? 'live in this project' : `${fmtN(M.indexed)} indexed`, '', MH('timeline')],
|
|
3422
3427
|
['Sessions', sessions, 'captured or remembered', '', MH('sessions')],
|
|
3423
|
-
['Pending', pending, pending ? `of ${events} evidence events` : `all ${events} distilled`, pending ? 'warn' : '', MH('health')],
|
|
3424
|
-
['Reused', M.reused, `${everywhere}${M.exposed} delivered`, '', MH('reuse')],
|
|
3428
|
+
['Pending', pending, pending ? `of ${fmtN(events)} evidence events` : `all ${fmtN(events)} distilled`, pending ? 'warn' : '', MH('health')],
|
|
3429
|
+
['Reused', M.reused, `${everywhere}${fmtN(M.exposed)} delivered`, '', MH('reuse')],
|
|
3425
3430
|
]);
|
|
3426
3431
|
}
|
|
3427
3432
|
|
|
@@ -3514,7 +3519,7 @@ function viewMemoryDashboard() {
|
|
|
3514
3519
|
|
|
3515
3520
|
return [
|
|
3516
3521
|
pageHead('What does memory hold?', [
|
|
3517
|
-
`${M.processed} distilled`, `${M.indexed} indexed`, `${M.reused} reused`, `${M.exposed} delivered`, `${M.assessed} assessed`,
|
|
3522
|
+
`${fmtN(M.processed)} distilled`, `${fmtN(M.indexed)} indexed`, `${fmtN(M.reused)} reused`, `${fmtN(M.exposed)} delivered`, `${fmtN(M.assessed)} assessed`,
|
|
3518
3523
|
], `Captured, processed, stored, retrieved, delivered, assessed — six different things that can happen to one
|
|
3519
3524
|
piece of evidence, counted separately. None of them is an answer: only a question you answered moves
|
|
3520
3525
|
mastery. Reuse, delivery and assessment are counted across all projects.`),
|
|
@@ -3738,13 +3743,13 @@ function viewHealth() {
|
|
|
3738
3743
|
!H.capture.enabled ? 'memory is disabled' : !H.capture.newest_event ? 'nothing has been captured yet' : '',
|
|
3739
3744
|
Q.failed ? `${plural(Q.failed, 'job')} failed after retries` : '',
|
|
3740
3745
|
Q.paused ? `${plural(Q.paused, 'job')} paused, waiting on a decision` : '',
|
|
3741
|
-
H.spool_dropped ? `${H.spool_dropped} events dropped by the spool` : '',
|
|
3746
|
+
H.spool_dropped ? `${fmtN(H.spool_dropped)} events dropped by the spool` : '',
|
|
3742
3747
|
].filter(Boolean);
|
|
3743
3748
|
return [
|
|
3744
3749
|
pageHead('Health', [
|
|
3745
3750
|
`last capture ${esc(H.capture.newest_event ? ago(H.capture.newest_event) : 'never')}`,
|
|
3746
3751
|
H.capture.enabled ? `capture is ${esc(H.capture.mode)}` : 'memory off',
|
|
3747
|
-
`${Q.pending} queued${Q.pending ? `, oldest ${esc(oldest)}` : ''}`,
|
|
3752
|
+
`${fmtN(Q.pending)} queued${Q.pending ? `, oldest ${esc(oldest)}` : ''}`,
|
|
3748
3753
|
], `Where memory stops, when it stops. Capture, processing, indexing, retrieval and delivery fail in
|
|
3749
3754
|
different ways and this page keeps them apart. Error classes only — no log dumps, no keys, no raw
|
|
3750
3755
|
request bodies. Transient failures retry on their own; auth, quota and missing need you.`),
|
|
@@ -4984,6 +4989,9 @@ function fbEmpty(F) {
|
|
|
4984
4989
|
} else if (F.failed) {
|
|
4985
4990
|
state = 'error';
|
|
4986
4991
|
body = `<p>Couldn't review the last session. It will try again at a later start.</p>`;
|
|
4992
|
+
} else if (F.acknowledged > 0) {
|
|
4993
|
+
state = 'happy';
|
|
4994
|
+
body = `<p>The next feedback is on its way. Eklavya will share it once it's available.</p>`;
|
|
4987
4995
|
} else {
|
|
4988
4996
|
body = `<p>Nothing to review yet. When a session ends, the next one you start reviews one of its prompts.</p>`;
|
|
4989
4997
|
}
|
|
@@ -5157,7 +5165,7 @@ const fbDecide = (it) => `<section class="card fb__card fb__decide" aria-labelle
|
|
|
5157
5165
|
<div class="fb__dh"><eklavya-mascot state="info" variant="face" size="32"></eklavya-mascot><h3 id="fb-decide-h">Done reading?</h3></div>
|
|
5158
5166
|
<p class="fb__dp">${esc(FB.rulePending)}</p>
|
|
5159
5167
|
${fbActions(it.id)}
|
|
5160
|
-
<p class="fb__foot"><span>1 waiting</span><span>${esc(S.feedback.acknowledged + ' in history')}</span></p></section>`;
|
|
5168
|
+
<p class="fb__foot"><span>1 waiting</span><span>${esc(fmtN(S.feedback.acknowledged) + ' in history')}</span></p></section>`;
|
|
5161
5169
|
|
|
5162
5170
|
/**
|
|
5163
5171
|
* One item: the verdict, the two prompts, what worked, what it left out and the
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eklavya",
|
|
3
3
|
"displayName": "Eklavya",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.77.0",
|
|
5
5
|
"description": "Learn while your agent works. Turns coding-agent generation time into adaptive, Socratic learning grounded in the code being written.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Ajay Kumar"
|
package/package.json
CHANGED