@nxuss/lemma 1.28.0 → 1.30.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.
Files changed (61) hide show
  1. package/README.md +41 -8
  2. package/bin/brain-ingest.js +34 -14
  3. package/dashboard/dist/assets/index-Dh-whqJ7.js +481 -0
  4. package/dashboard/dist/assets/index-Dh-whqJ7.js.map +1 -0
  5. package/dashboard/dist/assets/{index-DtEKr0hI.css → index-Yt1H2B7F.css} +1 -1
  6. package/dashboard/dist/index.html +2 -2
  7. package/dist/cjs/cli/hostHooks.d.ts +59 -0
  8. package/dist/cjs/cli/hostHooks.d.ts.map +1 -0
  9. package/dist/cjs/cli/hostHooks.js +235 -0
  10. package/dist/cjs/cli/hostHooks.js.map +1 -0
  11. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  12. package/dist/cjs/cli/lemma-proxy.js +31 -1
  13. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  14. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  15. package/dist/cjs/mcp/tools/memory.js +1 -0
  16. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  17. package/dist/cjs/subconscious/HostAdapters.d.ts +45 -0
  18. package/dist/cjs/subconscious/HostAdapters.d.ts.map +1 -0
  19. package/dist/cjs/subconscious/HostAdapters.js +219 -0
  20. package/dist/cjs/subconscious/HostAdapters.js.map +1 -0
  21. package/dist/cjs/subconscious/HostRecall.d.ts +44 -0
  22. package/dist/cjs/subconscious/HostRecall.d.ts.map +1 -0
  23. package/dist/cjs/subconscious/HostRecall.js +186 -0
  24. package/dist/cjs/subconscious/HostRecall.js.map +1 -0
  25. package/dist/cjs/subconscious/TheBrainV2.d.ts +21 -0
  26. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
  27. package/dist/cjs/subconscious/TheBrainV2.js +24 -2
  28. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
  29. package/dist/cjs/utils/FixCapture.d.ts +8 -0
  30. package/dist/cjs/utils/FixCapture.d.ts.map +1 -1
  31. package/dist/cjs/utils/FixCapture.js +14 -3
  32. package/dist/cjs/utils/FixCapture.js.map +1 -1
  33. package/dist/esm/cli/hostHooks.d.ts +59 -0
  34. package/dist/esm/cli/hostHooks.d.ts.map +1 -0
  35. package/dist/esm/cli/hostHooks.js +223 -0
  36. package/dist/esm/cli/hostHooks.js.map +1 -0
  37. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  38. package/dist/esm/cli/lemma-proxy.js +31 -1
  39. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  40. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  41. package/dist/esm/mcp/tools/memory.js +1 -0
  42. package/dist/esm/mcp/tools/memory.js.map +1 -1
  43. package/dist/esm/subconscious/HostAdapters.d.ts +45 -0
  44. package/dist/esm/subconscious/HostAdapters.d.ts.map +1 -0
  45. package/dist/esm/subconscious/HostAdapters.js +208 -0
  46. package/dist/esm/subconscious/HostAdapters.js.map +1 -0
  47. package/dist/esm/subconscious/HostRecall.d.ts +44 -0
  48. package/dist/esm/subconscious/HostRecall.d.ts.map +1 -0
  49. package/dist/esm/subconscious/HostRecall.js +178 -0
  50. package/dist/esm/subconscious/HostRecall.js.map +1 -0
  51. package/dist/esm/subconscious/TheBrainV2.d.ts +21 -0
  52. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
  53. package/dist/esm/subconscious/TheBrainV2.js +24 -2
  54. package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
  55. package/dist/esm/utils/FixCapture.d.ts +8 -0
  56. package/dist/esm/utils/FixCapture.d.ts.map +1 -1
  57. package/dist/esm/utils/FixCapture.js +13 -3
  58. package/dist/esm/utils/FixCapture.js.map +1 -1
  59. package/package.json +1 -1
  60. package/dashboard/dist/assets/index-DiidVeI5.js +0 -481
  61. package/dashboard/dist/assets/index-DiidVeI5.js.map +0 -1
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![MCP Tools](https://img.shields.io/badge/MCP%20tools-110-ff69b4?style=flat-square)](https://github.com/Nxusbets/lemma)
6
6
  [![Security](https://img.shields.io/badge/privacy-firewall%20active-blueviolet?style=flat-square)](https://github.com/Nxusbets/lemma)
7
7
  [![Caching](https://img.shields.io/badge/semantic%20memory-enabled-success?style=flat-square)](https://github.com/Nxusbets/lemma)
8
- [![Tests](https://img.shields.io/badge/tests-964%20passing-00c853?style=flat-square)](https://github.com/Nxusbets/lemma)
8
+ [![Tests](https://img.shields.io/badge/tests-987%20passing-00c853?style=flat-square)](https://github.com/Nxusbets/lemma)
9
9
 
10
10
  ```text
11
11
  __
@@ -35,6 +35,23 @@ lemma start # gateway + dashboard on http://localhost:8081
35
35
  >
36
36
  > **🆕 v1.22.0 — Lemma auto-activates in every LLM client.** `npm i -g @nxuss/lemma` registers the skill in your **user** catalog (auto-loads in every `muse` session, any project) and `lemma init` wires each project for Muse, Claude Code, Cursor, Codex, Windsurf, Kiro and OpenCode. Health check: `lemma doctor`.
37
37
  >
38
+ > **🆕 v1.30.0 — the Brain speaks through your agent's own tools, for zero tokens.** Agents read,
39
+ > edit and test with their native tools, so the Brain used to stay silent unless the model
40
+ > remembered `search_memory`. Now a post-tool hook answers at the three moments a memory is worth
41
+ > the most: reading a file the Brain has notes on (their ids), editing code where an approach
42
+ > already **failed**, and a test/build/lint failing with an error the Brain has a recorded **fix**
43
+ > for. Local BM25 + hashes, no model tokens; ids and one line only (~35 tokens), and silent by
44
+ > default — no match, a stale fix, or a note already given this session says nothing. `lemma init`
45
+ > wires it for **Claude Code, Codex, Cursor and OpenCode**. Also fixes `store()`'s dedup leaking
46
+ > across projects (the same fix in a second repo was dropped as a "duplicate").
47
+ >
48
+ > **🆕 v1.29.0 — the dashboard shows what the Brain knows.** `lemma start` now opens with a
49
+ > 🧠 Brain panel: how many files of your codebase it carries evidence about, how many times a
50
+ > memory reached an agent's context, growth this week, how much of it is verifiable against the
51
+ > code, where memories come from (manual, red → green fixes, tests, commits, team), and the most
52
+ > recalled ones. Token savings stay as a footnote — the Brain's value is agents not re-discovering
53
+ > context. Same numbers in `brain_stats` and at `GET /api/brain/stats`.
54
+ >
38
55
  > **🆕 v1.28.0 — the Brain goes team-wide through git, and fills itself.** `brain_team push`
39
56
  > writes your verified memories into the repo (`.lemma-brain/memories/`, one reviewable JSON file
40
57
  > each, paths relative to the repo root); `brain_team pull` — automatic on merge/checkout once
@@ -84,6 +101,16 @@ lemma start # gateway + dashboard on http://localhost:8081
84
101
  it, never one without the other). `store_memory` derives `filePaths`/`symbols` by default from
85
102
  whatever the session already read, wrote, or patched when the caller doesn't pass them —
86
103
  flagged as auto-derived in the response, correctable, but no longer opt-in.
104
+ - **A Brain that speaks up on its own, through the host's tools** — a post-tool hook
105
+ (`lemma-brain-ingest --hook-result --host=claude|codex|cursor|opencode`) points at memories when
106
+ the agent reads a file they're about to matter for, warns when an edit touches a documented
107
+ failed attempt, and names the recorded fix when a verdict command fails with an error already
108
+ fixed in *this* project (term overlap between error headlines decides "the same failure", not
109
+ BM25 rank). No model tokens to compute, ids instead of bodies, deduped per host session, and a
110
+ pointer never counts as reuse. Codex's shell reads (`cat`, `sed -n`, …) and `apply_patch` edits
111
+ are recovered from the command; OpenCode gets a plugin, since it has no hook protocol.
112
+ Windsurf/Devin post-hooks can't inject context, and Kiro's hooks spend tokens by design, so
113
+ neither is wired.
87
114
  - **A team Brain, shared through git** — `brain_team push` writes this project's fresh, tracked
88
115
  memories to `.lemma-brain/memories/<id>.json`: one sorted-key JSON file per memory, so two people
89
116
  sharing at once never conflict, every shared memory goes through code review, and deleting one is
@@ -194,8 +221,8 @@ lemma_toolbox { "action": "call", "tool": "terraform_drift", "args": {} }
194
221
 
195
222
  | Command | Action |
196
223
  | :--- | :--- |
197
- | `lemma init` | Bootstraps config, auto-configures MCP for OpenCode, Claude Desktop, Cursor, Windsurf, Kiro, VS Code, and installs the git hooks that feed the Brain (`--no-hooks` to skip). |
198
- | `lemma start` | Launches proxy, cache engine, and dashboard at `http://localhost:8081`. |
224
+ | `lemma init` | Bootstraps config, auto-configures MCP for OpenCode, Claude Desktop, Cursor, Windsurf, Kiro, VS Code, and installs the hooks that feed the Brain: git hooks, plus the tool hooks for Claude Code, Codex, Cursor and OpenCode (`--no-hooks` to skip). |
225
+ | `lemma start` | Launches proxy, cache engine, and dashboard at `http://localhost:8081` (gateway savings + Brain knowledge panel). |
199
226
  | `lemma stop` / `lemma status` / `lemma stats` | Stop, health check, and net token/cost report (reports `NET COST` when a session is underwater). |
200
227
  | `lemma mcp` | Starts the stdin/stdout MCP server for IDE integration. |
201
228
  | `lemma heal` / `lemma autopilot` / `lemma watch` | Diagnose+repair the last crash / toggle autonomous fix-apply / silent patch-only watcher. |
@@ -203,7 +230,7 @@ lemma_toolbox { "action": "call", "tool": "terraform_drift", "args": {} }
203
230
  | `lemma activate <key>` | Activate a Pro license. |
204
231
  | `lemma-checkpoint [projectRoot]` | Derive a session checkpoint from repo state (branch, changed files, commits) with no assistant call. |
205
232
  | `lemma-brain-ingest [projectRoot] [--changelog] [--team-pull]` | Feed The Brain from git commits and `CHANGELOG.md`, incrementally; `--team-pull` imports the repo's `.lemma-brain/`. |
206
- | `lemma-brain-ingest --hook-result` | Read a host `PostToolUse` payload on stdin and capture red → green fixes from the agent's own shell. |
233
+ | `lemma-brain-ingest --hook-result [--host=claude\|codex\|cursor\|opencode]` | Read a host post-tool payload on stdin: capture red → green fixes from the agent's own shell, and reply with a Brain note (memory ids, failed attempts, known fixes) in that host's format — or nothing. |
207
234
 
208
235
  Wire the standalone bins into hooks so memory doesn't depend on the assistant remembering to call a tool:
209
236
 
@@ -214,12 +241,18 @@ Wire the standalone bins into hooks so memory doesn't depend on the assistant re
214
241
  ```
215
242
 
216
243
  ```jsonc
217
- // .claude/settings.json — red → green fixes from Claude Code's own Bash tool become memories
218
- { "hooks": { "PostToolUse": [{ "matcher": "Bash", "hooks": [{ "type": "command",
219
- "command": "lemma-brain-ingest --hook-result" }] }] } }
244
+ // .claude/settings.local.json — what `lemma init` writes: fixes from Claude Code's own Bash
245
+ // become memories, and native Read/Edit/Bash get Brain notes back
246
+ { "hooks": { "PostToolUse": [{ "matcher": "Bash|Read|Edit|MultiEdit|Write|NotebookEdit",
247
+ "hooks": [{ "type": "command", "command": "lemma-brain-ingest --hook-result" }] }] } }
220
248
  ```
221
249
 
222
- The git side needs nothing by hand: `lemma init` installs `post-commit` (commit → memory) and
250
+ Codex (`~/.codex/hooks.json`, `--host=codex`), Cursor (`~/.cursor/hooks.json`, `postToolUse` +
251
+ `postToolUseFailure`, `--host=cursor`) and OpenCode (a plugin in `~/.config/opencode/plugins/`) are
252
+ wired the same way by `lemma init` when their config directory exists. Existing hooks are kept;
253
+ a file that isn't valid JSON is left alone and the snippet printed instead.
254
+
255
+ The git side needs nothing by hand either: `lemma init` installs `post-commit` (commit → memory) and
223
256
  `post-merge`/`post-checkout` (pull the team's `.lemma-brain/`). With a versioned hooks dir
224
257
  (`core.hooksPath`, e.g. husky) it prints the lines to add instead of editing team files.
225
258
 
@@ -14,13 +14,20 @@
14
14
  * and never double-store. `--max N` only matters the first time there is no marker yet.
15
15
  *
16
16
  * Usage: lemma-brain-ingest [projectRoot] [--max N] [--changelog] [--no-commits] [--team-pull]
17
- * lemma-brain-ingest --hook-result < payload.json
17
+ * lemma-brain-ingest --hook-result [--host=claude|codex|cursor|opencode] < payload.json
18
18
  *
19
19
  * --team-pull Import the repo's shared memories from .lemma-brain/ (post-merge/post-checkout).
20
- * --hook-result Read a host PostToolUse hook payload on stdin (Claude Code's Bash tool shape) and
21
- * feed it to FixCapture, so a test that goes red → green through the agent's own
22
- * shell becomes a memory too. Wire it in .claude/settings.json:
23
- * "hooks": { "PostToolUse": [{ "matcher": "Bash",
20
+ * --hook-result Read a host PostToolUse hook payload on stdin (Claude Code shape) and:
21
+ * - feed a Bash run to FixCapture, so a test that goes red → green through the
22
+ * agent's own shell becomes a memory too;
23
+ * - answer with a HostRecall note (as `additionalContext`, the only PostToolUse
24
+ * output the host puts in the model's context) when a Read touches a file the
25
+ * Brain has memories about, an edit touches a documented failed attempt, or a
26
+ * failing verdict command matches a recorded fix. Silent otherwise.
27
+ * --host=claude|codex|cursor|opencode picks the payload/reply dialect
28
+ * (default claude; see src/subconscious/HostAdapters.ts).
29
+ * `lemma init` wires it for each host it finds, e.g. .claude/settings.local.json:
30
+ * "hooks": { "PostToolUse": [{ "matcher": "Bash|Read|Edit|MultiEdit|Write|NotebookEdit",
24
31
  * "hooks": [{ "type": "command", "command": "lemma-brain-ingest --hook-result" }] }] }
25
32
  */
26
33
 
@@ -34,27 +41,40 @@ function readStdin() {
34
41
  }
35
42
  }
36
43
 
37
- function hookResult() {
38
- const distPath = path.join(__dirname, '..', 'dist', 'cjs', 'utils', 'FixCapture.js');
39
- let recordHookPayload;
44
+ function hookResult(args) {
45
+ const dist = path.join(__dirname, '..', 'dist', 'cjs');
46
+ let recordHookPayload, recallForHookPayload, normalizeHostPayload, formatHostOutput, parseHost;
40
47
  try {
41
- ({ recordHookPayload } = require(distPath));
48
+ ({ recordHookPayload } = require(path.join(dist, 'utils', 'FixCapture.js')));
49
+ ({ recallForHookPayload } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
50
+ ({ normalizeHostPayload, formatHostOutput, parseHost } = require(path.join(dist, 'subconscious', 'HostAdapters.js')));
42
51
  } catch {
43
52
  return; // no build — a hook must stay silent and harmless
44
53
  }
45
- let payload;
54
+ const hostArg = args.find((a) => a.startsWith('--host='));
55
+ const host = parseHost(hostArg ? hostArg.slice('--host='.length) : undefined);
56
+ let raw;
46
57
  try {
47
- payload = JSON.parse(readStdin());
58
+ raw = JSON.parse(readStdin());
48
59
  } catch {
49
60
  return;
50
61
  }
51
- const res = recordHookPayload(payload, payload && payload.cwd);
52
- if (res && res.captured) console.error(res.note.trim());
62
+ const notes = [];
63
+ for (const payload of normalizeHostPayload(host, raw)) {
64
+ try {
65
+ const res = recordHookPayload(payload, payload.cwd);
66
+ if (res && res.captured) console.error(res.note.trim());
67
+ } catch { /* capture failing must not cost the recall below */ }
68
+ const note = recallForHookPayload(payload, payload.cwd);
69
+ if (note && !notes.includes(note)) notes.push(note);
70
+ }
71
+ const out = formatHostOutput(host, notes.join('\n'));
72
+ if (out) process.stdout.write(out);
53
73
  }
54
74
 
55
75
  function main() {
56
76
  const args = process.argv.slice(2);
57
- if (args.includes('--hook-result')) return hookResult();
77
+ if (args.includes('--hook-result')) return hookResult(args);
58
78
  const maxIndex = args.indexOf('--max');
59
79
  const maxCommits = maxIndex >= 0 ? parseInt(args[maxIndex + 1], 10) : undefined;
60
80
  const includeChangelog = args.includes('--changelog');