eklavya 1.27.0 → 1.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,27 +1,29 @@
1
- # eklavya
1
+ # Eklavya
2
2
 
3
- [Eklavya](https://github.com/ProjectAJ14/eklavya) — learn while your agent works. This package is
4
- the whole thing: the installer, the MCP server, the CLI, and the Claude Code plugin it installs.
3
+ [Eklavya](https://github.com/ProjectAJ14/eklavya) teaches the concepts behind
4
+ agent-written code and keeps local project memory. This package includes the
5
+ Claude Code plugin, installer, CLI and MCP server.
5
6
 
6
- ## Install
7
+ ## Install in Claude Code
8
+
9
+ With Node 22 or newer:
7
10
 
8
11
  ```bash
9
12
  npx eklavya install
10
13
  ```
11
14
 
12
- That checks your Node version, installs the runtime and its SQLite driver, registers the plugin
13
- with Claude Code and enables it, installs the chat skill into `~/.claude/skills/`, and creates the
14
- database. Restart Claude Code afterwards, then run `/eklavya:setup` to pick a mode. Re-running it
15
- is how you upgrade; `npx eklavya uninstall` removes it and keeps your history unless you pass
16
- `--purge`.
15
+ Follow the settings prompts, then restart Claude Code. The installer registers
16
+ the plugin, installs the managed runtime and chat/artifact skills, and prepares
17
+ local storage. `/eklavya:setup` lets you revisit settings.
17
18
 
18
- Requires **Node 22+** — below that the SQLite driver has no prebuilt binary and would need a C++
19
- toolchain to compile.
19
+ Read the [installation guide](https://eklavya-run.web.app/docs/installing/) for
20
+ verification and [updates and removal](https://eklavya-run.web.app/docs/updates/)
21
+ for maintenance. Uninstall preserves learner data unless you explicitly use
22
+ `--purge`.
20
23
 
21
- ## As a standalone MCP server
24
+ ## Standalone MCP connection
22
25
 
23
- The server runs on its own, so any MCP client can use it — this is what makes Eklavya
24
- editor-agnostic.
26
+ An MCP client can connect directly:
25
27
 
26
28
  ```json
27
29
  {
@@ -31,41 +33,45 @@ editor-agnostic.
31
33
  }
32
34
  ```
33
35
 
34
- > Renamed from `eklavya-mcp` after 1.7.0, and the separate `eklavya-mcp` binary folded into
35
- > `eklavya serve` at the same time — one package, one command. The old package still exists on
36
- > npm so older installs keep resolving, but it is no longer updated.
36
+ This exposes tools. Automatic capture, checkpoints and session instructions
37
+ depend on host integration; an MCP connection alone does not provide Claude
38
+ Code's learning loop.
37
39
 
38
- State lives in `~/.eklavya/knowledge.db` (SQLite, WAL). Override with `EKLAVYA_HOME` or `EKLAVYA_DB`.
40
+ ## Available tools
39
41
 
40
- ## Tools
41
-
42
- | Tool | Purpose |
42
+ | Purpose | Tools |
43
43
  |---|---|
44
- | `get_learner_profile` | what the developer already knows; call before teaching |
45
- | `log_session_concepts` | record what the current task exercises, with code context |
46
- | `get_session_quiz_plan` | what to ask, and at which difficulty tier |
47
- | `record_attempt` | grade 0–5, update mastery and the review schedule |
48
- | `get_gate_status` | whether this session's quiz gate has passed |
49
- | `upsert_concepts` | grow the graph, with slug normalization and dedupe |
50
- | `get_concept_graph` | a domain in prerequisite order |
51
- | `get_config` / `set_config` | global and per-repo settings |
44
+ | Learner state and concepts | `get_learner_profile`, `log_session_concepts`, `upsert_concepts`, `get_concept_graph` |
45
+ | Questions and assessment | `get_session_quiz_plan`, `record_attempt`, `get_gate_status` |
46
+ | Settings | `get_config`, `set_config` |
47
+ | Find and read memory | `memory_search`, `memory_get`, `memory_timeline`, `memory_file_history`, `memory_status` |
48
+ | Maintain memory | `memory_write`, `memory_correct`, `memory_delete`, `memory_collections` |
49
+ | Inspect code | `code_outline`, `code_find_symbol` |
52
50
 
53
- `session_id` is optional on every tool — the server resolves the current session itself.
51
+ Search first, choose relevant entries, then use `memory_get` for their full
52
+ content. Session-aware learning and configuration tools resolve the current session
53
+ when `session_id` is omitted. In `memory_timeline`, it instead filters results
54
+ to one session; omission shows the project timeline. Other tools may not accept
55
+ that argument.
54
56
 
55
- ## CLI
57
+ ## CLI and data
56
58
 
57
59
  ```bash
58
- eklavya install # install into Claude Code, runtime included
59
- eklavya uninstall [--purge] # remove it; --purge also deletes your history
60
- eklavya doctor # check the install
61
- eklavya config get
62
- eklavya config set quiz.enforced true [--project] # gate commits on one codebase
63
- eklavya config set focus concept # what it teaches
64
- eklavya config set focus learn --topic caching
65
- eklavya export-rules --out rules.md # the tutor pedagogy as Markdown
66
- eklavya dashboard [--port <n>] [--no-open] # your learning history, served locally and opened
67
- # in your browser (--no-open just prints the URL)
68
- eklavya db-path
60
+ npx eklavya doctor
61
+ npx eklavya memory status
62
+ npx eklavya config get
63
+ npx eklavya dashboard
64
+ npx eklavya db-path
69
65
  ```
70
66
 
67
+ The [CLI reference](https://eklavya-run.web.app/docs/cli/) lists all commands and
68
+ flags. [Configuration](https://eklavya-run.web.app/docs/configuration/) lists
69
+ defaults and scopes. The [memory guide](https://eklavya-run.web.app/docs/memory/)
70
+ covers retrieval, processing, providers, privacy and sync.
71
+
72
+ State is local under `~/.eklavya/`, including `knowledge.db` (SQLite, WAL).
73
+ `EKLAVYA_HOME` and `EKLAVYA_DB` override those paths. Questions and memory have
74
+ independent switches. External processing is optional and explicitly configured;
75
+ see [your data](https://eklavya-run.web.app/docs/your-data/).
76
+
71
77
  MIT.
package/dist/artifacts.js CHANGED
@@ -64,8 +64,8 @@ function inlineTokens() {
64
64
  return css.replace(/@import\s+url\([^)]*\)[^;]*;\s*/gi, '');
65
65
  }
66
66
  catch {
67
- // A build without the tokens still yields a readable page: the template's
68
- // own fallbacks cover the roles it names.
67
+ // A build without the tokens still writes the page; it renders unstyled
68
+ // until the tokens are restored, rather than failing the command.
69
69
  return '';
70
70
  }
71
71
  }
@@ -1 +1 @@
1
- {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"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"}
@@ -20,7 +20,7 @@
20
20
  /*{{TOKENS}}*/
21
21
  </style>
22
22
  <style>
23
- :root{ --ok:var(--spot); --maxw:880px; }
23
+ :root{ --maxw:880px; }
24
24
 
25
25
  *{box-sizing:border-box}
26
26
  body{margin:0;background:var(--bg);color:var(--ink);font:15px/1.65 var(--font-body)}
@@ -80,7 +80,7 @@
80
80
  border:1px solid var(--line-2);border-radius:0;background:var(--panel);color:var(--ink);
81
81
  font:500 12px var(--font-mono);letter-spacing:.06em;cursor:pointer}
82
82
  .actions button:hover{border-color:var(--spot);color:var(--spot)}
83
- .actions button:focus-visible{outline:none;box-shadow:0 0 0 2px var(--bg),0 0 0 4px var(--spot)}
83
+ .actions button:focus-visible{outline:none;box-shadow:var(--ring)}
84
84
 
85
85
  @media screen{
86
86
  body{background-image:linear-gradient(var(--grid) 1px,transparent 1px),
@@ -97,7 +97,7 @@
97
97
  the viewport, so it never opens off-screen on a phone or a short window. */
98
98
  .picker { position:fixed; z-index:40; min-width:220px; max-width:calc(100vw - 16px);
99
99
  background:var(--panel); border:1px solid var(--line-2); padding:var(--space-1) 0;
100
- box-shadow:0 12px 32px rgba(0,0,0,.28); overflow-y:auto; }
100
+ box-shadow:var(--shadow-lg); overflow-y:auto; }
101
101
  .picker[hidden] { display:none; }
102
102
  .picker__label { font-family:var(--font-mono); font-size:10px; letter-spacing:var(--tracking-caps);
103
103
  text-transform:uppercase; color:var(--faint); padding:var(--space-2) var(--space-4) var(--space-1); margin:0; }
@@ -105,7 +105,7 @@
105
105
  background:none; border:0; color:var(--dim); font:inherit; font-size:14px;
106
106
  padding:var(--space-2) var(--space-4); cursor:pointer; }
107
107
  .picker button:hover, .picker button:focus-visible { background:var(--mass); color:var(--ink); box-shadow:none; outline:none; }
108
- .picker button:focus-visible { box-shadow:inset 2px 0 0 var(--spot); }
108
+ .picker button:focus-visible { box-shadow:inset 2px 0 0 var(--spot); } /* inset: the picker scrolls, so an outset ring would clip */
109
109
  .picker button[aria-checked="true"] { color:var(--ink); }
110
110
  .picker button span { flex:1; }
111
111
  .picker .check { width:15px; height:15px; color:var(--spot); visibility:hidden; }
@@ -119,6 +119,8 @@
119
119
  transition:color var(--duration-fast) var(--ease), background var(--duration-fast) var(--ease); }
120
120
  nav.side__nav a:hover { color:var(--ink); background:var(--mass); }
121
121
  nav.side__nav a[aria-current="page"] { color:var(--ink); border-left-color:var(--spot); background:var(--mass); }
122
+ /* --faint misses 4.5:1 on --mass in ink */
123
+ nav.side__nav a[aria-current="page"] i, nav.side__nav a:hover i { color:var(--dim); }
122
124
  nav.side__nav a svg { width:17px; height:17px; flex:none; color:var(--faint); }
123
125
  nav.side__nav a[aria-current="page"] svg { color:var(--spot); }
124
126
  nav.side__nav a i { margin-left:auto; font-style:normal; font-family:var(--font-mono);
@@ -266,10 +268,10 @@
266
268
  .meter.mute > i { background:var(--faint-2); }
267
269
 
268
270
  .pill { display:inline-block; font-family:var(--font-mono); font-size:11px; padding:2px 8px;
269
- border-radius:var(--radius-pill); background:var(--mass); color:var(--dim); white-space:nowrap; }
271
+ border-radius:0; background:var(--mass); color:var(--dim); white-space:nowrap; }
270
272
  .pill.ok { background:var(--spot-soft); color:var(--spot); }
271
273
  .pill.due { color:var(--warning); }
272
- .pill.new { color:var(--faint); }
274
+ .pill.new { color:var(--dim); }
273
275
 
274
276
  .grade { font-family:var(--font-mono); font-size:11.5px; padding:2px 8px; white-space:nowrap;
275
277
  background:var(--mass); color:var(--dim); }
@@ -286,7 +288,7 @@
286
288
  .seg > span { display:block; height:100%; }
287
289
  .seg__key { display:flex; gap:var(--space-5); flex-wrap:wrap; margin-top:var(--space-3);
288
290
  font-size:12.5px; color:var(--dim); }
289
- .seg__key b { display:inline-block; width:9px; height:9px; margin-right:var(--space-2); }
291
+ .seg__key b { display:inline-block; width:9px; height:9px; margin-right:var(--space-2); border:1px solid var(--line-2); }
290
292
 
291
293
  /* ---------- charts ---------- */
292
294
  .legend { display:flex; gap:var(--space-5); font-size:12.5px; color:var(--dim);
@@ -298,6 +300,7 @@
298
300
  .axis { font-family:var(--font-mono); font-size:10px; fill:var(--faint); }
299
301
  .hit { fill:transparent; cursor:pointer; }
300
302
  .hit:hover + .col, .hit:focus-visible + .col { opacity:.72; }
303
+ .hit:focus-visible { outline:2px solid var(--spot); outline-offset:-2px; }
301
304
  .tip { position:absolute; pointer-events:none; opacity:0; transform:translate(-50%,-100%);
302
305
  background:var(--bg); border:1px solid var(--line-2); color:var(--ink);
303
306
  padding:var(--space-3); font-size:var(--text-xs); line-height:1.6; white-space:nowrap;
@@ -393,7 +396,7 @@
393
396
  background:none; border:1px solid var(--line-2); color:var(--ink); width:34px; height:34px; cursor:pointer; }
394
397
  .side__close svg { width:16px; height:16px; }
395
398
  .side__brand { padding-right:64px; }
396
- .scrim { position:fixed; inset:0; z-index:25; background:rgba(0,0,0,.45); }
399
+ .scrim { position:fixed; inset:0; z-index:25; background:color-mix(in srgb, var(--bg) 70%, transparent); }
397
400
  .scrim.is-open { display:block; }
398
401
  body.drawer-open { overflow:hidden; }
399
402
  main { padding:var(--space-6) var(--space-5) var(--space-16); }
@@ -1119,7 +1122,7 @@ function viewLearningDashboard() {
1119
1122
  ${card('Where you stand', 'The catalogue is a library, not a to-do list — untouched concepts are not debt.',
1120
1123
  segbar([
1121
1124
  { label:'Mastered', n:mastered.length, color:'var(--spot)' },
1122
- { label:'Learning', n:seen.length - mastered.length, color:'var(--warning)' },
1125
+ { label:'Learning', n:seen.length - mastered.length, color:'color-mix(in srgb, var(--spot) 45%, var(--mass))' },
1123
1126
  { label:'Not asked', n:Math.max(0, scoped.length - seen.length), color:'var(--mass)' },
1124
1127
  ]) + `<p style="margin:var(--space-4) 0 0;color:var(--faint);font-size:13.5px">
1125
1128
  A concept is mastered at score 0.7 with two or more passes. Score decays about
@@ -1699,7 +1702,7 @@ function viewDomain(name) {
1699
1702
  </div>`,
1700
1703
  card(null, null, segbar([
1701
1704
  { label:'Mastered', n:seen.filter((c) => c.mastered).length, color:'var(--spot)' },
1702
- { label:'Learning', n:seen.filter((c) => !c.mastered).length, color:'var(--warning)' },
1705
+ { label:'Learning', n:seen.filter((c) => !c.mastered).length, color:'color-mix(in srgb, var(--spot) 45%, var(--mass))' },
1703
1706
  { label:'Not asked', n:all.length - seen.length, color:'var(--mass)' },
1704
1707
  ])),
1705
1708
  card(null, null, table([{t:'Concept'},{t:'Tier'},{t:'Score'},{t:'Asked',n:1},{t:'State'},{t:'From your code'}], rows)
@@ -2497,7 +2500,7 @@ function renderNav(wf, active) {
2497
2500
  const id = `grp-${wf}-${g.id}`;
2498
2501
  return `<div class="nav__group">
2499
2502
  <button type="button" class="nav__toggle" id="tog-${wf}-${g.id}" data-group="${g.id}" aria-expanded="${open}" aria-controls="${id}">
2500
- <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>${esc(g.label)}
2503
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>${esc(g.label)}
2501
2504
  </button>
2502
2505
  <div class="nav__items" id="${id}" role="group" aria-label="${esc(g.label)}"${open ? '' : ' hidden'}>${g.items.map(item).join('')}</div>
2503
2506
  </div>`;
@@ -40,10 +40,9 @@
40
40
  --vd-900: #052E2B;
41
41
 
42
42
  /* ---------- SEMANTIC (real errors and warnings only) ----------
43
- Kept off the accent hue so state never reads as branding. Both are
44
- redefined per ground below: an orange that carries on ink is 2.3:1 on
45
- cream, which fails as text and as a chart fill alike. */
46
- --error: #E5484D;
43
+ Kept off the accent hue so state never reads as branding. --warning and
44
+ --error are redefined per ground below: an orange that carries on ink is
45
+ 2.3:1 on cream, which fails as text and as a chart fill alike. */
47
46
  --info: #4A9EFF;
48
47
 
49
48
  /* ---------- TYPE FAMILIES ----------
@@ -144,6 +143,7 @@
144
143
  --glow-low: rgba(25,150,136,.10);
145
144
  --shot-op: .28; /* the arrow scene, as ambient art */
146
145
  --warning: #E8920C;
146
+ --error: #FF6166; /* 4.82:1 on its own 12% tint over --panel */
147
147
  --code-bg: var(--mass); /* the well behind a code block */
148
148
  --shadow-lg: 0 12px 28px rgba(0,0,0,.45);
149
149
  --ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--spot);
@@ -173,6 +173,7 @@
173
173
  --glow-low: rgba(14,110,102,.05);
174
174
  --shot-op: .5;
175
175
  --warning: #7A4B00; /* 5.21:1 on --mass */
176
+ --error: #A8201A; /* 4.70:1 on its own 12% tint over --panel */
176
177
  /* A syntax theme's dimmest token (comments) lands at 3.9:1 on --mass. The
177
178
  well is lightened rather than the theme repainted, which lifts every
178
179
  token at once; the frame's border is what still reads it as a block. */
@@ -197,4 +198,5 @@
197
198
  --term-spot: var(--vd-300);
198
199
  --term-cmd: #8ECF7A;
199
200
  --term-str: #E6C060;
201
+ --term-err: #E5484D;
200
202
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eklavya",
3
3
  "displayName": "Eklavya",
4
- "version": "1.27.0",
4
+ "version": "1.27.1",
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"
@@ -47,9 +47,11 @@ In this order, each under its own `<h2>`:
47
47
  - **The rule that transfers.** When this applies in a different codebase, and
48
48
  the one gotcha to watch for.
49
49
 
50
- Plain English, short sentences, no jargon without a gloss. Role tokens only in
51
- any CSS you add (`--ink --dim --line --spot …`), square corners, no emoji, one
52
- self-contained file.
50
+ Plain English, short sentences, no jargon without a gloss. Any CSS you add
51
+ follows the design rules in the `eklavya-artifacts` skill: role tokens only
52
+ (`--ink --dim --faint --line --spot …`, never a raw hex or `--vd-*` step), one
53
+ verdigris accent, square corners, hairlines instead of shadows, the three font
54
+ variables, readable on both ink and paper, no emoji. One self-contained file.
53
55
 
54
56
  Never reveal or restate the answer to a *different* question, and never grade
55
57
  anything: the session already recorded the answer.
@@ -1,110 +1,62 @@
1
1
  # Working in `cli/`
2
2
 
3
- **This directory is not the `eklavya` binary.** That is `mcp/src/cli.ts`,
4
- published as `dist/cli.js` and the package's only `bin`. `cli/` holds exactly one
5
- file: `eklavya-gate`, the POSIX commit-gate script. The name invites the
6
- confusion, so check which one a request means before you edit anything —
7
- `eklavya config`, `eklavya doctor`, `eklavya dashboard` and `eklavya install` all
8
- live in `mcp/src/cli.ts`.
9
-
10
- It is a shell script and not Node on purpose: it runs as a git `pre-commit` hook
11
- on every commit, and a git hook must not pay Node's startup cost. Keep it POSIX
12
- `sh` — the installed hook execs it with `#!/bin/sh`, and `mcp/test/gate.test.ts`
13
- drives it through `/bin/sh`.
14
-
15
- ## It is opt-in, twice over
16
-
17
- Nothing in `eklavya install` puts this on a repo. `scripts/install-git-hook.sh`
18
- does, as a separate step the user runs per repo; it writes `pre-commit` in the
19
- **common** git directory's `hooks/` (so a linked worktree gets the main
20
- checkout's hook, which is the one git runs), between the `# >>> eklavya gate >>>`
21
- markers, and if a `pre-commit` already existed it moves it to `pre-commit.local`
22
- and chains it first. `--uninstall` restores it. Re-running it rewrites an older
23
- Eklavya hook in place. With `core.hooksPath` set (husky, lefthook) it installs
24
- nothing, prints the line to add to the manager's hook, and exits 2.
25
-
26
- The installed hook does not `exec` this file at a fixed path any more. It runs
27
- the first that exists of `~/.eklavya/runtime/node_modules/eklavya/dist/plugin/cli/eklavya-gate`
28
- (honouring `EKLAVYA_RUNTIME` and `EKLAVYA_HOME`) and the path the installer ran
29
- from, with `sh` so a lost executable bit cannot block. If neither exists the
30
- commit goes through with one stderr line. The old fixed-path `exec` meant a
31
- plugin update that moved the directory made every commit fail — the one failure
32
- this gate must never have. `eklavya uninstall` warns about the hook and prints
33
- the command to remove it; it never deletes it.
34
-
35
- Then the script itself only acts on a project whose config sets `quiz.enforced`
36
- (or the retired `"mode": "enforced"`, which it still reads). That config is at
37
- `~/.eklavya/projects/<slug>/config.json` — the script rebuilds the slug itself,
38
- in shell, from `git rev-parse --show-toplevel` folded to the main checkout via
39
- `--git-common-dir`, because a worktree shares its parent's settings. Note that it
40
- reads enforcement from **only** the project file — not `~/.eklavya/config.json` —
41
- so a globally set gate does not hold a bare terminal. The global file is read for
42
- one thing: a `quiz.enabled: false` (or `mode: off`) there, not overridden by the
43
- project, releases the gate, exactly as `coerce()` does — otherwise a terminal
44
- commit is held by a gate no quiz will ever run to clear. The slug path is built
45
- with `pwd -P` so a checkout reached through a symlink still finds its file.
46
-
47
- It reads `<repo>/.eklavya.json` as a fallback and does **not** migrate it. The
48
- node half moves that file out automatically; a git pre-commit hook is the wrong
49
- place to start rewriting somebody's working tree, so it reads the old location
50
- and lets the next ordinary session do the move. Any doc claiming a terminal commit is gated has to attach the installer
51
- step and the repo config; `web/src/content/docs/docs/commit-gate.mdx` and
52
- `skills/setup/SKILL.md` are where that lives.
53
-
54
- ## It fails open, always
55
-
56
- A learning tool that bricks commits gets uninstalled, and an unpassable gate
57
- teaches nothing. Every one of these exits 0:
58
-
59
- - not inside a git repo, or `git rev-parse` fails;
60
- - no config for this project, at either the current or the legacy location;
61
- - `jq` not on PATH (warns on stderr) — **or** `sqlite3` not on PATH (warns too).
62
- It needs both, not just `jq`;
63
- - the config does not ask for enforcement — `quiz.enforced` false or absent with
64
- no `mode: enforced` behind it, or `quiz.enabled` false — in the project file,
65
- or in the global one when the project does not say;
66
- - the database file does not exist;
67
- - the `sqlite3` query errors, or returns no gate row for this repo.
68
-
69
- Exit 1 happens on exactly one condition: a gate row for this repo whose `passed`
70
- is not `1`. Adding a new failure mode means adding a new `exit 0` path.
71
-
72
- ## It reads the database directly
73
-
74
- There is no server in a git hook, so the script talks to `knowledge.db` in raw
75
- SQL and duplicates things it cannot import. Keep it in step with:
76
-
77
- - the `gates` table shape — it selects `passed, required, answered` and picks the
78
- repo's most recent row by `updated_at`. `syncGate` in `mcp/src/store.ts` is the
79
- only writer; a renamed or added column lands here in the same commit.
80
- - `DEFAULT_CONFIG.quiz` in `mcp/src/config.ts` — the script defaults a config
81
- with neither `quiz` nor `mode` to unenforced.
82
- - `projectSlug` in `mcp/src/paths.ts` — the script rebuilds it with
83
- `tr '/\\:' '-'`, and `test/gate.test.ts` runs both parsers over one set of
84
- configs so the two cannot drift apart silently.
85
- - the `mode` → `quiz` alias in `normalizeLegacyKeys`, and the rule that
86
- `quiz.enabled: false` forces `enforced` off. Both are duplicated here in jq,
87
- spelled out with `if`/`elif` rather than `//`: jq's `//` is an alternative
88
- operator, so `.quiz.enforced // (.mode == "enforced")` reads an explicit
89
- `false` as unset and falls back to a stale `mode` in the same file — a gate
90
- that keeps holding commits after somebody switched it off.
91
- `test/gate.test.ts` runs both parsers over the same five configs.
92
-
93
- The pass/fail arithmetic itself (`PASSING_GRADE`, `pass_threshold`,
94
- `ceil(required * pass_threshold)`) is **not** duplicated here — the script trusts
95
- the persisted `passed` column. Keep it that way: a change to the gate's rule
96
- belongs in `syncGate` alone. What is duplicated is the lookup key, and it differs
97
- from the in-session hook on purpose: `mcp/src/hooks/pre-tool-gate.ts` looks the
98
- gate up by `session_id`, this script by `repo`, because a terminal commit has no
99
- session.
100
-
101
- ## Tests
102
-
103
- `mcp/test/gate.test.ts` runs the real script and the real installer against a
104
- temp repo, and ends with an actual `git commit`. From `mcp/`:
105
-
106
- ```sh
107
- npm test -- gate
108
- ```
109
-
110
- `pretest` builds `dist/`, which `pre-tool-gate.js` in the same file needs.
3
+ This directory contains the POSIX `eklavya-gate` script. The `eklavya` binary
4
+ (`config`, `doctor`, `install`, `dashboard`, etc.) lives in `mcp/src/cli.ts`.
5
+ Read the root `CLAUDE.md` for the repository contract.
6
+
7
+ ## Installation and scope
8
+
9
+ The terminal gate requires both a per-repository installation and project
10
+ `quiz.enforced: true`. `eklavya install` does not install a git hook.
11
+
12
+ `scripts/install-git-hook.sh` writes into the common Git directory so linked
13
+ worktrees use the same hook. It preserves an existing hook as `pre-commit.local`
14
+ and runs that first; `--uninstall` restores it. With `core.hooksPath` configured,
15
+ it prints the integration line and exits 2 without installing anything.
16
+
17
+ The installed wrapper tries the managed runtime, then the original installation
18
+ path, and invokes the script with `sh`. Missing both paths warns and allows the
19
+ commit. Preserve this fallback: updates can move plugin directories.
20
+ `eklavya uninstall` warns about the hook and prints removal instructions; it
21
+ does not remove the hook itself.
22
+
23
+ Project config lives in `~/.eklavya/projects/<slug>/config.json`; worktrees fold
24
+ to their main checkout. The script reads the old `<repo>/.eklavya.json` only as
25
+ a fallback and never migrates it. Global enforcement alone does not activate
26
+ this gate, but a global `quiz.enabled: false` releases it unless overridden by
27
+ the project. Keep legacy `mode` compatibility and explicit `false` values.
28
+
29
+ ## Fail-open contract
30
+
31
+ Use POSIX `sh`; the installed hook runs through `/bin/sh`. Missing repository,
32
+ config, `jq`, `sqlite3`, database or gate row allows the commit. Database query
33
+ errors also allow it. Missing dependencies warn on stderr.
34
+
35
+ Exit 1 only when a gate row exists for this repository and `passed` is not `1`.
36
+ Do not add an operational error that prevents a commit.
37
+
38
+ ## Keep duplicated logic aligned
39
+
40
+ | Script responsibility | Source and verification |
41
+ |---|---|
42
+ | Config merge and legacy `mode` alias | `mcp/src/config.ts`; shared fixtures in `mcp/test/gate.test.ts` |
43
+ | Project slug and worktree folding | `mcp/src/paths.ts`; physical paths must also handle symlinks |
44
+ | Latest repository gate lookup | `gates` schema and `syncGate` in `mcp/src/store.ts` |
45
+ | In-session commit detection | `mcp/src/hooks/pre-tool-gate.ts` and `commit-lib.ts` |
46
+
47
+ The script trusts persisted `passed`; it must not duplicate passing-grade or
48
+ threshold arithmetic. It looks up the latest gate by repository, whereas the
49
+ in-session hook uses a session ID. In jq, use explicit `if`/`elif` for booleans:
50
+ `//` treats `false` as absent and can re-enable a disabled legacy gate.
51
+
52
+ ## Documentation and verification
53
+
54
+ In the same PR, update the manual `commit-gate.mdx` for installer, prerequisite,
55
+ scope, bypass or failure behavior changes. Check `configuration.mdx`,
56
+ `skills/setup/SKILL.md` and the commit-gate acceptance check in `CONTRIBUTING.md`
57
+ when their claims change. Every claim about terminal enforcement must include
58
+ both installation and project enforcement.
59
+
60
+ From `mcp/`, run `npm test -- gate`. It builds the runtime and exercises the real
61
+ script and installer in temporary repositories, including an actual commit.
62
+ Build `web/` after documentation changes; report any live acceptance test not run.