@nxuss/lemma 1.19.0 → 1.21.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 (50) hide show
  1. package/.agents/skills/lemma/SKILL.md +124 -0
  2. package/README.md +5 -1
  3. package/bin/init.js +109 -29
  4. package/bin/lemma-call.js +269 -0
  5. package/dist/cjs/mcp/index.js +4 -2
  6. package/dist/cjs/mcp/index.js.map +1 -1
  7. package/dist/cjs/mcp/prompts.d.ts +1 -1
  8. package/dist/cjs/mcp/prompts.d.ts.map +1 -1
  9. package/dist/cjs/mcp/prompts.js +1 -1
  10. package/dist/cjs/mcp/tool-profiles.d.ts.map +1 -1
  11. package/dist/cjs/mcp/tool-profiles.js +9 -0
  12. package/dist/cjs/mcp/tool-profiles.js.map +1 -1
  13. package/dist/cjs/mcp/tools/analysis.d.ts.map +1 -1
  14. package/dist/cjs/mcp/tools/analysis.js +51 -20
  15. package/dist/cjs/mcp/tools/analysis.js.map +1 -1
  16. package/dist/cjs/mcp/tools/memory.d.ts +4 -4
  17. package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
  18. package/dist/cjs/mcp/tools/memory.js +217 -11
  19. package/dist/cjs/mcp/tools/memory.js.map +1 -1
  20. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  21. package/dist/cjs/mcp/tools.js +4 -1
  22. package/dist/cjs/mcp/tools.js.map +1 -1
  23. package/dist/cjs/subconscious/TheBrainV2.d.ts +102 -1
  24. package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
  25. package/dist/cjs/subconscious/TheBrainV2.js +255 -10
  26. package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
  27. package/dist/esm/mcp/index.js +4 -2
  28. package/dist/esm/mcp/index.js.map +1 -1
  29. package/dist/esm/mcp/prompts.d.ts +1 -1
  30. package/dist/esm/mcp/prompts.d.ts.map +1 -1
  31. package/dist/esm/mcp/prompts.js +1 -1
  32. package/dist/esm/mcp/tool-profiles.d.ts.map +1 -1
  33. package/dist/esm/mcp/tool-profiles.js +9 -0
  34. package/dist/esm/mcp/tool-profiles.js.map +1 -1
  35. package/dist/esm/mcp/tools/analysis.d.ts.map +1 -1
  36. package/dist/esm/mcp/tools/analysis.js +52 -21
  37. package/dist/esm/mcp/tools/analysis.js.map +1 -1
  38. package/dist/esm/mcp/tools/memory.d.ts +4 -4
  39. package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
  40. package/dist/esm/mcp/tools/memory.js +217 -11
  41. package/dist/esm/mcp/tools/memory.js.map +1 -1
  42. package/dist/esm/mcp/tools.d.ts.map +1 -1
  43. package/dist/esm/mcp/tools.js +4 -1
  44. package/dist/esm/mcp/tools.js.map +1 -1
  45. package/dist/esm/subconscious/TheBrainV2.d.ts +102 -1
  46. package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
  47. package/dist/esm/subconscious/TheBrainV2.js +253 -10
  48. package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
  49. package/lemma-proxy.cjs +12 -0
  50. package/package.json +11 -2
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: lemma
3
+ description: Lemma — cache semántico, firewall de privacidad y memoria cross-sesión para Muse. Usa `lemma call <tool>` vía bash para acceder a 70+ tools sin MCP nativo.
4
+ user-invocable: true
5
+ allowed-tools: bash
6
+ ---
7
+
8
+ # Lemma para Muse
9
+
10
+ Eres Muse Code (muse-spark). Tienes **Lemma MCP** disponible — gateway de caché semántica, firewall de privacidad y memoria persistente. Muse no expone MCP nativamente, así que llamas a Lemma vía **CLI `lemma call`** (wrapper sobre `mcp-server.js` por stdio) + **proxy local**.
11
+
12
+ ## Qué es Lemma
13
+
14
+ - **Proxy local** en `http://localhost:8081` — cachea respuestas LLM (BM25 + embeddings), ahorra tokens/dinero.
15
+ - **Brain persistente** en `~/.lemma-cache/lemma_brain.json` + memoria por proyecto.
16
+ - **MCP server** con 70+ tools — las mismas que usan Claude Code / Cursor / Codex, aquí vía `lemma call`.
17
+
18
+ > **Nota de compatibilidad:** Este skill NO afecta a Claude Code, Cursor, Codex ni otros CLIs con MCP nativo. Ellos siguen usando `mcp__lemma__*` directo. Las reglas globales de `AGENTS.md` (MANDATORY RULES) aplican a clientes con MCP nativo; si eres Muse, **este skill tiene prioridad** sobre `AGENTS.md` para decidir cuándo usar Lemma.
19
+
20
+ ## Cuándo usar Lemma (Muse)
21
+
22
+ | Tarea | Qué hacer con Lemma |
23
+ |---|---|
24
+ | Pregunta que puede estar ya resuelta | `search_memory` antes de razonar |
25
+ | Pregunta atada a archivos concretos (mismo prompt + mismos archivos) | `state_hash_cache` con `action=lookup` antes, `store` después |
26
+ | Conocimiento que debe sobrevivir sesiones | `search_memory` / `store_memory` (con `derivedFrom`) |
27
+ | Leer/listar/buscar workspace | Usa tus tools nativos (`read_file`, `bash ls/grep`) — Lemma añade scrubbing si lo llamas, pero no es obligatorio |
28
+ | Tarea mecánica → decidir modelo barato | `get_routing_advice` |
29
+ | Aplicar patch | `validate_patch_sandbox` primero |
30
+ | "¿Cuánto ahorramos?" | `token_receipt` |
31
+
32
+ Si Lemma no encaja, usa tu tool nativo. No fuerces Lemma donde no aporta.
33
+
34
+ ## Cómo llamar a Lemma desde Muse (preferido)
35
+
36
+ Usa el wrapper `lemma call` — evita craft de JSON-RPC manual y escapa args por ti. Está disponible como `node ./lemma-proxy.cjs call` o `node ./bin/lemma-call.js` o `npx @nxuss/lemma call` si instalaste global.
37
+
38
+ ```bash
39
+ # 1. Lookup en memoria antes de razonar (preferido — wrapper)
40
+ node ./lemma-proxy.cjs call search_memory --query "tu pregunta"
41
+ # o JSON explícito:
42
+ node ./lemma-proxy.cjs call search_memory '{"query":"tu pregunta"}'
43
+
44
+ # 2. Busca en workspace (con scrubbing)
45
+ node ./lemma-proxy.cjs call search_workspace --query "texto" --maxResults 10
46
+
47
+ # 3. Guarda solución verificada
48
+ node ./lemma-proxy.cjs call store_memory '{"content":"solución verificada","tags":["bugfix"]}'
49
+
50
+ # 4. Lista tools disponibles
51
+ node ./lemma-proxy.cjs call --list
52
+
53
+ # Pipe también funciona:
54
+ echo '{"query":"hello"}' | node ./bin/lemma-call.js search_memory
55
+ ```
56
+
57
+ **Alternativa raw (solo si el wrapper no está disponible):**
58
+
59
+ ```bash
60
+ echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_memory","arguments":{"query":"tu pregunta"}}}' | node ./mcp-server.js
61
+ ```
62
+
63
+ Para tráfico LLM real (cache del proxy), asegúrate que el daemon corre:
64
+
65
+ ```bash
66
+ node ./lemma-proxy.cjs status
67
+ node ./lemma-proxy.cjs start
68
+ ```
69
+
70
+ ## Cero config en este repo
71
+
72
+ Si clonaste `lemma` y lo abriste con Muse, **no necesitas correr ningún comando**. Este repo ya trae:
73
+ - `.agents/skills/lemma/SKILL.md` (este archivo) — Muse lo detecta al abrir el workspace
74
+ - `AGENTS.md` con guard clause para Muse
75
+ - `bin/lemma-call.js` + `lemma-proxy.cjs call` (wrapper sin JSON manual)
76
+ - `mcp-server.js` como fallback sin build
77
+
78
+ Muse te pedirá confiar el workspace la primera vez (prompt interactivo). Una vez que aceptas, el skill queda activo automáticamente — sin `lemma init`, sin `npm run build` manual. Para uso total (70+ tools) el wrapper resuelve `dist/cjs/mcp/index.js` → `mcp-server.js`; si `dist` no existe se auto-construye o usa el fallback con las tools core.
79
+
80
+ ## Sandbox y permisos
81
+
82
+ Muse corre con sandbox por workspace. El proxy (`localhost:8081`) y el brain (`~/.lemma-cache/`) están **fuera** del workspace, así que:
83
+
84
+ - La primera vez Muse pregunta si confías el workspace — di que sí. Después queda recordado, no necesitas `--trust-workspace` manual cada vez (solo si lo abres con flag explícito).
85
+ - Si ves `permission denied`, acepta el trust prompt y re-intenta; no necesitas `--disable-sandbox`.
86
+ - El wrapper prioriza `dist/cjs/mcp/index.js` y cae a `mcp-server.js` si aún no hay build — cero pasos extra.
87
+
88
+ ## Flujo obligatorio al iniciar sesión
89
+
90
+ 1. Llama `search_memory` vía `lemma call` con el tema de la tarea.
91
+ 2. Si hay hit, verifícalo contra el código actual antes de presentarlo.
92
+ 3. Al terminar con solución verificada (tests pasaron), llama `store_memory` vía `lemma call`.
93
+
94
+ ## Flujo para bugs
95
+
96
+ 1. `get_telepathic_hints` vía `lemma call` si necesitas contexto de runtime.
97
+ 2. `search_memory` con el mensaje de error.
98
+
99
+ ## Regla dura
100
+
101
+ Si tu respuesta viene de un cache hit, dilo explícitamente: "esto viene de memoria cacheada". Nunca presentes un hit como razonamiento fresco. Y nunca guardes una solución no verificada.
102
+
103
+ ## Verificación (opcional)
104
+
105
+ En este repo no necesitas instalar nada — ya está listo. Solo si quieres verificar:
106
+
107
+ ```bash
108
+ # Wrapper responde (sin JSON manual)
109
+ node ./lemma-proxy.cjs call --list | head -c 500
110
+ node ./lemma-proxy.cjs call get_project_onboarding '{}' | head -c 800
111
+
112
+ # Proxy (solo si usas cache de tráfico LLM)
113
+ node ./lemma-proxy.cjs status
114
+ ```
115
+
116
+ Para **otros proyectos** (no este repo), instala Lemma una vez:
117
+
118
+ ```bash
119
+ npx @nxuss/lemma init # genera .agents/skills/lemma/SKILL.md + AGENTS.md en ese proyecto
120
+ # o
121
+ npm i -D @nxuss/lemma && npx lemma init
122
+ ```
123
+
124
+ > Generado por `lemma init` — @nxuss/lemma para Muse.
package/README.md CHANGED
@@ -27,10 +27,12 @@ to an auditable ledger, never an estimate.
27
27
 
28
28
  ```bash
29
29
  npm install -g @nxuss/lemma
30
- lemma init # auto-configures MCP for your IDE
30
+ lemma init # auto-configures MCP for your IDE (Claude Code, Cursor, Codex, Windsurf, Kiro, OpenCode)
31
31
  lemma start # gateway + dashboard on http://localhost:8081
32
32
  ```
33
33
 
34
+ > **Muse** — no setup needed. This repo is already Muse-compatible zero-config: clone and open with `muse` — the skill at `.agents/skills/lemma/SKILL.md` auto-loads and `lemma call` works via `bash`. See [MCP integration](#-mcp-integration).
35
+
34
36
  ---
35
37
 
36
38
  ## ✨ What Lemma actually does
@@ -154,9 +156,11 @@ Customize via `lemma.config.json`:
154
156
 
155
157
  | Client | Setup |
156
158
  | :--- | :--- |
159
+ | **Muse** (`muse` CLI · Muse Spark) | **Zero-config** — clone this repo and open with `muse`; skill at `.agents/skills/lemma/SKILL.md` auto-loads, `lemma call` wrapper via `bash` (no MCP native needed). No `lemma init` required. |
157
160
  | OpenCode | `lemma init` — registers itself in `~/.opencode.json`, zero config. |
158
161
  | Cursor / Windsurf / Kiro / Antigravity | Settings → MCP → add server, command `lemma mcp`. |
159
162
  | Claude Desktop | Add to `mcpServers`: `{ "lemma": { "command": "npx", "args": ["-y", "@nxuss/lemma", "mcp"] } }` |
163
+ | Claude Code / Codex CLI | `lemma init` — auto-configures MCP + sets gateway (`ANTHROPIC_BASE_URL`/`OPENAI_BASE_URL` → `http://localhost:8081`). |
160
164
 
161
165
  Once connected, Lemma auto-injects its TurboMode system prompt on handshake — states the goal
162
166
  (reduce what enters context without ever costing a correct answer) and enforces it: a tool call
package/bin/init.js CHANGED
@@ -205,7 +205,7 @@ function configureClaudeDesktop() {
205
205
  const FALLBACK_LEMMA_TOOL_NAMES = [
206
206
  'read_workspace_file', 'write_workspace_file', 'create_workspace_file', 'list_workspace_dir',
207
207
  'search_workspace', 'apply_workspace_patch', 'run_workspace_command', 'output_region',
208
- 'search_memory', 'store_memory', 'smarter_cache',
208
+ 'search_memory', 'get_memory', 'store_memory', 'update_memory', 'smarter_cache',
209
209
  'get_project_onboarding', 'get_telepathic_hints', 'get_ast_hologram',
210
210
  'get_symbol_surgical_context', 'compress_context',
211
211
  'squeeze_prompt', 'turbosqueeze', 'wormhole_squeeze',
@@ -282,11 +282,14 @@ tokens sale más cara que los tokens que ahorra.
282
282
  | Agregar un método/función a un archivo existente | \`mcp__lemma__surgical_ast_insert\` | Patch quirúrgico en vez de reescribir el archivo completo |
283
283
  | Antes de aplicar un patch generado | \`mcp__lemma__validate_patch_sandbox\` | Valídalo antes de escribirlo, no después |
284
284
  | "¿Cuánto ahorramos de verdad?" | \`mcp__lemma__token_receipt\` | Bitácora auditable real, no una cifra inventada |
285
+ | Leer una memoria por su id (antes de editarla, o para un id que traes de otra sesión) | \`mcp__lemma__get_memory\` | Lectura determinista: \`search_memory\` es un ranking y puede no devolver la entrada que buscas. Editar un documento vivo sin leerlo antes es editarlo a ciegas |
286
+ | Corregir o extender una memoria que ya existe | \`mcp__lemma__update_memory\` | Reescribe en su sitio conservando id, hits y las aristas \`derivedFrom\`. \`store_memory\` siempre crea un id nuevo: re-guardar una versión corregida deja las dos y la búsqueda devuelve una mezcla arbitraria de ambas |
285
287
  | Guardar una solución para el futuro | \`mcp__lemma__store_memory\` | Solo después de verificarla (tests pasaron, el usuario confirmó) — una solución mala guardada se vuelve un cache hit falso más adelante |
286
288
  | Una memoria salió STALE pero la verificaste y sigue siendo correcta | \`mcp__lemma__refresh_memory\` | Re-ancla la evidencia conservando id, hits y las aristas \`derivedFrom\`; guardar un casi-duplicado pierde las tres (y el dedup suele rechazarlo) |
287
289
  | Una memoria está simplemente mal, no solo mal encajada | \`mcp__lemma__forget_memory\` | Borrado real. Para "no era lo que buscaba en esta consulta" usa \`downvote_memory\`: esa memoria puede ser la correcta para otra pregunta |
288
290
 
289
- Ambas están en el toolbox (\`action="call"\`), no en la lista anunciada.
291
+ El ciclo de vida completo (\`search\` \`get\` \`update\`/\`refresh\`/\`forget\`) está anunciado:
292
+ ante una memoria desactualizada, corrígela; no guardes otra al lado.
290
293
 
291
294
  ## No todas las tools de Lemma están en tu lista
292
295
 
@@ -427,9 +430,18 @@ function configureClaudeCodeGateway(anthropicApiKey) {
427
430
 
428
431
  const LEMMA_RULES_CONTENT = `# Lemma MCP — Autonomous Behaviors
429
432
 
430
- > ⚠️ MANDATORY RULES — Follow without exception.
433
+ > ⚠️ MANDATORY RULES — Follow without exception **for MCP-native clients**.
431
434
 
432
- The MCP server \`lemma\` is connected. NEVER use native tools when a Lemma equivalent exists.
435
+ The MCP server \`lemma\` is connected. For clients with native MCP support
436
+ (Claude Code, Cursor, Codex, Windsurf, Kiro, OpenCode), NEVER use native tools
437
+ when a Lemma equivalent exists.
438
+
439
+ > **Muse Code:** you DO NOT have native \`mcp__lemma__*\` tools. For you,
440
+ > \`AGENTS.md\` is advisory. Follow \`.agents/skills/lemma/SKILL.md\` instead —
441
+ > it has priority and uses \`lemma call\` via bash. Do not enforce the table
442
+ > below as a hard block; use it only when \`lemma call\` actually helps.
443
+
444
+ ## Mandatory Substitutions (MCP-native clients only)
433
445
 
434
446
  ## Mandatory Substitutions
435
447
 
@@ -452,6 +464,8 @@ The MCP server \`lemma\` is connected. NEVER use native tools when a Lemma equiv
452
464
  2. Call \`search_memory\` with the task topic — recall past solutions
453
465
  3. When done: call \`store_memory\` with the solution
454
466
 
467
+ > Muse: use \`node ./lemma-proxy.cjs call <tool>\` (see \`.agents/skills/lemma/SKILL.md\`).
468
+
455
469
  ## Bug Reporting
456
470
 
457
471
  1. Call \`get_telepathic_hints\` with the relevant file
@@ -474,6 +488,17 @@ function updateAgentsMd() {
474
488
  const existing = fs.readFileSync(agentsMdPath, 'utf8');
475
489
  if (!existing.includes('@nxuss/lemma')) {
476
490
  fs.appendFileSync(agentsMdPath, '\n---\n\n' + LEMMA_RULES_CONTENT, 'utf8');
491
+ } else if (!existing.includes('Muse Code:') || !existing.includes('MCP-native clients')) {
492
+ // Migrate old Lemma AGENTS.md (pre-Muse guard) to new version with Muse compatibility
493
+ // Replace the old block in-place to preserve any user content above it
494
+ const lemmaBlockRegex = /# Lemma MCP[\s\S]*?\*Auto-generated by `lemma init` — @nxuss\/lemma\*/;
495
+ if (lemmaBlockRegex.test(existing)) {
496
+ const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
497
+ fs.writeFileSync(agentsMdPath, updated, 'utf8');
498
+ } else {
499
+ // Fallback: append new block
500
+ fs.appendFileSync(agentsMdPath, '\n---\n\n' + LEMMA_RULES_CONTENT, 'utf8');
501
+ }
477
502
  }
478
503
  } else {
479
504
  fs.writeFileSync(agentsMdPath, LEMMA_RULES_CONTENT, 'utf8');
@@ -546,21 +571,25 @@ function configureKiro() {
546
571
  return true;
547
572
  }
548
573
 
549
- // OpenCode: register MCP server in opencode.json
574
+ // OpenCode: register MCP server in opencode.json + Muse skill
550
575
  const MUSE_SKILL_CONTENT = `---
551
576
  name: lemma
552
- description: Lemma — cache semántico, firewall de privacidad y memoria cross-sesión para Muse.
577
+ description: Lemma — cache semántico, firewall de privacidad y memoria cross-sesión para Muse. Usa lemma call <tool> vía bash para acceder a 70+ tools sin MCP nativo.
578
+ user-invocable: true
579
+ allowed-tools: bash
553
580
  ---
554
581
 
555
582
  # Lemma para Muse
556
583
 
557
- Eres Muse Code (muse-spark). Tienes disponible **Lemma MCP** — gateway de caché semántica, firewall de privacidad y memoria persistente. Este skill te enseña a usarlo sin MCP nativo (Muse no habla MCP aún): todo es vía CLI + proxy local.
584
+ Eres Muse Code (muse-spark). Tienes **Lemma MCP** disponible — gateway de caché semántica, firewall de privacidad y memoria persistente. Muse no expone MCP nativamente, así que llamas a Lemma vía **CLI \`lemma call\`** (wrapper sobre \`mcp-server.js\` por stdio) + **proxy local**.
558
585
 
559
586
  ## Qué es Lemma
560
587
 
561
588
  - **Proxy local** en \`http://localhost:8081\` — cachea respuestas LLM (BM25 + embeddings), ahorra tokens/dinero.
562
589
  - **Brain persistente** en \`~/.lemma-cache/lemma_brain.json\` + memoria por proyecto.
563
- - **MCP server** con 70+ tools — las mismas que usan Claude Code / Cursor / Codex, pero aquí las llamas vía \`npx @nxuss/lemma\` o \`node mcp-server.js\` por \`bash\`.
590
+ - **MCP server** con 70+ tools — las mismas que usan Claude Code / Cursor / Codex, aquí vía \`lemma call\`.
591
+
592
+ > **Nota de compatibilidad:** Este skill NO afecta a Claude Code, Cursor, Codex ni otros CLIs con MCP nativo. Ellos siguen usando \`mcp__lemma__*\` directo. Las reglas globales de \`AGENTS.md\` (MANDATORY RULES) aplican a clientes con MCP nativo; si eres Muse, **este skill tiene prioridad** sobre \`AGENTS.md\` para decidir cuándo usar Lemma.
564
593
 
565
594
  ## Cuándo usar Lemma (Muse)
566
595
 
@@ -576,61 +605,94 @@ Eres Muse Code (muse-spark). Tienes disponible **Lemma MCP** — gateway de cach
576
605
 
577
606
  Si Lemma no encaja, usa tu tool nativo. No fuerces Lemma donde no aporta.
578
607
 
579
- ## Cómo llamar a Lemma desde Muse
608
+ ## Cómo llamar a Lemma desde Muse (preferido)
580
609
 
581
- Muse no tiene \`mcp__lemma__*\` tools nativas. Llama al servidor MCP por **stdio** vía bash:
610
+ Usa el wrapper \`lemma call\` evita craft de JSON-RPC manual y escapa args por ti. Está disponible como \`node ./lemma-proxy.cjs call\` o \`node ./bin/lemma-call.js\` o \`npx @nxuss/lemma call\` si instalaste global.
582
611
 
583
612
  \`\`\`bash
584
- # 1. Lookup en memoria antes de razonar
585
- echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_memory","arguments":{"query":"tu pregunta"}}}' | node ./mcp-server.js
613
+ # 1. Lookup en memoria antes de razonar (preferido — wrapper)
614
+ node ./lemma-proxy.cjs call search_memory --query "tu pregunta"
615
+ # o JSON explícito:
616
+ node ./lemma-proxy.cjs call search_memory '{"query":"tu pregunta"}'
586
617
 
587
- # 2. Tool genérico - busca en workspace (con scrubbing)
588
- echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"search_workspace","arguments":{"query":"texto"}}}' | node ./mcp-server.js
618
+ # 2. Busca en workspace (con scrubbing)
619
+ node ./lemma-proxy.cjs call search_workspace --query "texto" --maxResults 10
589
620
 
590
621
  # 3. Guarda solución verificada
591
- echo '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"store_memory","arguments":{"content":"solución verificada","tags":["bugfix"]}}}' | node ./mcp-server.js
622
+ node ./lemma-proxy.cjs call store_memory '{"content":"solución verificada","tags":["bugfix"]}'
623
+
624
+ # 4. Lista tools disponibles
625
+ node ./lemma-proxy.cjs call --list
626
+
627
+ # Pipe también funciona:
628
+ echo '{"query":"hello"}' | node ./bin/lemma-call.js search_memory
592
629
  \`\`\`
593
630
 
594
- O usa el wrapper más simple si está instalado:
631
+ **Alternativa raw (solo si el wrapper no está disponible):**
595
632
 
596
633
  \`\`\`bash
597
- npx -y @nxuss/lemma mcp # servidor MCP stdio
598
- lemma search "query" # CLI directa si instalaste lemma global
634
+ echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_memory","arguments":{"query":"tu pregunta"}}}' | node ./mcp-server.js
599
635
  \`\`\`
600
636
 
601
- Para el proxy de cache (tráfico LLM real), asegúrate que el daemon corre:
637
+ Para tráfico LLM real (cache del proxy), asegúrate que el daemon corre:
602
638
 
603
639
  \`\`\`bash
604
640
  node ./lemma-proxy.cjs status
605
641
  node ./lemma-proxy.cjs start
606
642
  \`\`\`
607
643
 
644
+ ## Cero config en este repo
645
+
646
+ Si clonaste \`lemma\` y lo abriste con Muse, **no necesitas correr ningún comando**. Este repo ya trae:
647
+ - \`.agents/skills/lemma/SKILL.md\` (este archivo) — Muse lo detecta al abrir el workspace
648
+ - \`AGENTS.md\` con guard clause para Muse
649
+ - \`bin/lemma-call.js\` + \`lemma-proxy.cjs call\` (wrapper sin JSON manual)
650
+ - \`mcp-server.js\` como fallback sin build
651
+
652
+ Muse te pedirá confiar el workspace la primera vez (prompt interactivo). Una vez que aceptas, el skill queda activo automáticamente — sin \`lemma init\`, sin \`npm run build\` manual. Para uso total (70+ tools) el wrapper resuelve \`dist/cjs/mcp/index.js\` → \`mcp-server.js\`; si \`dist\` no existe se auto-construye o usa el fallback con las tools core.
653
+
654
+ ## Sandbox y permisos
655
+
656
+ Muse corre con sandbox por workspace. El proxy (\`localhost:8081\`) y el brain (\`~/.lemma-cache/\`) están **fuera** del workspace, así que:
657
+
658
+ - La primera vez Muse pregunta si confías el workspace — di que sí. Después queda recordado, no necesitas \`--trust-workspace\` manual cada vez (solo si lo abres con flag explícito).
659
+ - Si ves \`permission denied\`, acepta el trust prompt y re-intenta; no necesitas \`--disable-sandbox\`.
660
+ - El wrapper prioriza \`dist/cjs/mcp/index.js\` y cae a \`mcp-server.js\` si aún no hay build — cero pasos extra.
661
+
608
662
  ## Flujo obligatorio al iniciar sesión
609
663
 
610
- 1. Llama \`search_memory\` con el tema de la tarea.
664
+ 1. Llama \`search_memory\` vía \`lemma call\` con el tema de la tarea.
611
665
  2. Si hay hit, verifícalo contra el código actual antes de presentarlo.
612
- 3. Al terminar con solución verificada (tests pasaron), llama \`store_memory\`.
666
+ 3. Al terminar con solución verificada (tests pasaron), llama \`store_memory\` vía \`lemma call\`.
613
667
 
614
668
  ## Flujo para bugs
615
669
 
616
- 1. \`get_telepathic_hints\` si necesitas contexto de runtime.
670
+ 1. \`get_telepathic_hints\` vía \`lemma call\` si necesitas contexto de runtime.
617
671
  2. \`search_memory\` con el mensaje de error.
618
672
 
619
673
  ## Regla dura
620
674
 
621
675
  Si tu respuesta viene de un cache hit, dilo explícitamente: "esto viene de memoria cacheada". Nunca presentes un hit como razonamiento fresco. Y nunca guardes una solución no verificada.
622
676
 
623
- ## Instalación / verificación
677
+ ## Verificación (opcional)
678
+
679
+ En este repo no necesitas instalar nada — ya está listo. Solo si quieres verificar:
624
680
 
625
681
  \`\`\`bash
626
- # Re-configura todo (incluye Muse skill)
627
- node ./bin/init.js
682
+ # Wrapper responde (sin JSON manual)
683
+ node ./lemma-proxy.cjs call --list | head -c 500
684
+ node ./lemma-proxy.cjs call get_project_onboarding '{}' | head -c 800
628
685
 
629
- # Verifica que el proxy está arriba
630
- curl -s http://localhost:8081/health || echo "proxy down"
686
+ # Proxy (solo si usas cache de tráfico LLM)
687
+ node ./lemma-proxy.cjs status
688
+ \`\`\`
631
689
 
632
- # Verifica MCP responde
633
- echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node ./mcp-server.js | head -c 500
690
+ Para **otros proyectos** (no este repo), instala Lemma una vez:
691
+
692
+ \`\`\`bash
693
+ npx @nxuss/lemma init # genera .agents/skills/lemma/SKILL.md + AGENTS.md en ese proyecto
694
+ # o
695
+ npm i -D @nxuss/lemma && npx lemma init
634
696
  \`\`\`
635
697
 
636
698
  > Generado por \`lemma init\` — @nxuss/lemma para Muse.
@@ -647,6 +709,24 @@ function configureMuse() {
647
709
  } catch { return false; }
648
710
  }
649
711
 
712
+ function ensureKiroMigratesAgentsMd() {
713
+ // Kiro's configureKiro also touches AGENTS.md — ensure it migrates the same way
714
+ const cwd = process.cwd();
715
+ const agentsMdPath = path.join(cwd, 'AGENTS.md');
716
+ try {
717
+ if (fs.existsSync(agentsMdPath)) {
718
+ const existing = fs.readFileSync(agentsMdPath, 'utf8');
719
+ if (existing.includes('@nxuss/lemma') && (!existing.includes('Muse Code:') || !existing.includes('MCP-native clients'))) {
720
+ const lemmaBlockRegex = /# Lemma MCP[\s\S]*?\*Auto-generated by `lemma init` — @nxuss\/lemma\*/;
721
+ if (lemmaBlockRegex.test(existing)) {
722
+ const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
723
+ fs.writeFileSync(agentsMdPath, updated, 'utf8');
724
+ }
725
+ }
726
+ }
727
+ } catch {}
728
+ }
729
+
650
730
  function configureOpenCode() {
651
731
  const cwd = process.cwd();
652
732
  const opencodePath = path.join(cwd, 'opencode.json');
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Lemma Call — one-shot MCP tool invocation for CLIs without native MCP (Muse, etc.)
6
+ *
7
+ * Usage:
8
+ * node bin/lemma-call.js <tool_name> [json_args]
9
+ * node bin/lemma-call.js search_memory '{"query":"hello"}'
10
+ * echo '{"query":"hello"}' | node bin/lemma-call.js search_memory
11
+ * node bin/lemma-call.js --list # lists available tools
12
+ *
13
+ * Also via npx:
14
+ * npx @nxuss/lemma call search_memory '{"query":"hello"}'
15
+ *
16
+ * Resolves MCP server path the same way as bin/init.js and mcp-server.js:
17
+ * 1. dist/cjs/mcp/index.js (built)
18
+ * 2. mcp-server.js (fallback/legacy)
19
+ */
20
+
21
+ const fs = require('fs');
22
+ const path = require('path');
23
+ const { spawn } = require('child_process');
24
+
25
+ function resolveMcpServer() {
26
+ const candidates = [
27
+ path.join(__dirname, '..', 'dist', 'cjs', 'mcp', 'index.js'),
28
+ path.join(__dirname, '..', 'mcp-server.js'),
29
+ path.join(__dirname, 'mcp-server.js'),
30
+ ];
31
+ for (const p of candidates) {
32
+ if (fs.existsSync(p)) return p;
33
+ }
34
+ // Zero-config: try to auto-build dist if missing and tsc is available (fresh clone without build)
35
+ try {
36
+ const pkgPath = path.join(__dirname, '..', 'package.json');
37
+ if (fs.existsSync(pkgPath)) {
38
+ const { execSync } = require('child_process');
39
+ // Only attempt if typescript is installed (npm install was run)
40
+ execSync('npx tsc --project tsconfig.cjs.json --outDir ./dist/cjs 2>&1', { cwd: path.join(__dirname, '..'), stdio: 'ignore', timeout: 30000 });
41
+ const built = path.join(__dirname, '..', 'dist', 'cjs', 'mcp', 'index.js');
42
+ if (fs.existsSync(built)) return built;
43
+ }
44
+ } catch {}
45
+ return null;
46
+ }
47
+
48
+ function parseArgs(argv) {
49
+ const args = argv.slice(2);
50
+ if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
51
+ return { help: true };
52
+ }
53
+ if (args.includes('--list') || args.includes('--tools')) {
54
+ return { list: true };
55
+ }
56
+ // tool name is first non-flag arg
57
+ let tool = null;
58
+ let jsonArg = null;
59
+ const flags = {};
60
+ for (let i = 0; i < args.length; i++) {
61
+ const a = args[i];
62
+ if (a.startsWith('--')) {
63
+ const key = a.slice(2);
64
+ const next = args[i + 1];
65
+ if (next && !next.startsWith('--')) {
66
+ flags[key] = next;
67
+ i++;
68
+ } else {
69
+ flags[key] = true;
70
+ }
71
+ } else if (!tool) {
72
+ tool = a;
73
+ } else if (!jsonArg) {
74
+ jsonArg = a;
75
+ }
76
+ }
77
+ // Flags like --query "hello" should become jsonArg object
78
+ let jsonObj = null;
79
+ if (jsonArg) {
80
+ try { jsonObj = JSON.parse(jsonArg); } catch (e) {
81
+ console.error(`[lemma-call] Invalid JSON args: ${e.message}`);
82
+ process.exit(2);
83
+ }
84
+ } else if (Object.keys(flags).length > 0) {
85
+ jsonObj = flags;
86
+ // coerce common string flags
87
+ for (const k of Object.keys(jsonObj)) {
88
+ if (jsonObj[k] === 'true') jsonObj[k] = true;
89
+ if (jsonObj[k] === 'false') jsonObj[k] = false;
90
+ }
91
+ }
92
+ return { tool, jsonObj, flags };
93
+ }
94
+
95
+ function readStdin() {
96
+ return new Promise(resolve => {
97
+ if (process.stdin.isTTY) return resolve(null);
98
+ let data = '';
99
+ process.stdin.setEncoding('utf8');
100
+ process.stdin.on('data', chunk => data += chunk);
101
+ process.stdin.on('end', () => {
102
+ const t = data.trim();
103
+ if (!t) return resolve(null);
104
+ try { resolve(JSON.parse(t)); } catch { resolve(t); }
105
+ });
106
+ // If stdin never ends (no pipe), timeout
107
+ setTimeout(() => resolve(null), 100);
108
+ });
109
+ }
110
+
111
+ async function main() {
112
+ const parsed = parseArgs(process.argv);
113
+ if (parsed.help) {
114
+ console.log(`lemma-call — one-shot Lemma MCP tool invocation
115
+
116
+ Usage:
117
+ node bin/lemma-call.js <tool> [json]
118
+ node bin/lemma-call.js search_memory '{"query":"hello"}'
119
+ node bin/lemma-call.js search_memory --query "hello"
120
+ echo '{"query":"hello"}' | node bin/lemma-call.js search_memory
121
+ node bin/lemma-call.js --list
122
+ npx @nxuss/lemma call <tool> [json] (via lemma-proxy.cjs)
123
+ `);
124
+ process.exit(0);
125
+ }
126
+
127
+ const mcpPath = resolveMcpServer();
128
+ if (!mcpPath) {
129
+ console.error('[lemma-call] MCP server not found. Run `npm run build` first.');
130
+ process.exit(1);
131
+ }
132
+
133
+ // --list mode: proper MCP handshake (initialize → tools/list)
134
+ if (parsed.list) {
135
+ const initReq = JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'lemma-call', version: '1.0.0' } } }) + '\n';
136
+ const initialized = JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' }) + '\n';
137
+ const listReq = JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'tools/list' }) + '\n';
138
+ const child = spawn(process.execPath, [mcpPath], { stdio: ['pipe', 'pipe', 'pipe'] });
139
+ let out = '';
140
+ child.stdout.on('data', d => out += d.toString());
141
+ child.stderr.on('data', () => {}); // ignore watcher noise
142
+ child.stdin.write(initReq);
143
+ child.stdin.write(initialized);
144
+ child.stdin.write(listReq);
145
+ child.stdin.end();
146
+ // Give server time to respond before close (MCP is stream-oriented)
147
+ await new Promise(r => setTimeout(r, 800));
148
+ try { child.kill(); } catch {}
149
+ await new Promise(r => child.on('close', r).on('error', r));
150
+ // Parse all JSON-RPC response lines, find the tools/list result (id:2)
151
+ const lines = out.trim().split('\n').filter(Boolean);
152
+ let tools = null;
153
+ for (const line of lines) {
154
+ try {
155
+ const j = JSON.parse(line);
156
+ if (j.id === 2 && j.result && Array.isArray(j.result.tools)) { tools = j.result.tools; break; }
157
+ if (j.result && Array.isArray(j.result.tools) && !tools) tools = j.result.tools;
158
+ } catch {}
159
+ }
160
+ if (tools) {
161
+ console.log(JSON.stringify(tools.map(t => t.name), null, 2));
162
+ } else {
163
+ // Fallback: try last line approach
164
+ try {
165
+ const res = JSON.parse(lines[lines.length - 1] || '{}');
166
+ const t = res.result?.tools || [];
167
+ if (t.length) console.log(JSON.stringify(t.map(x => x.name), null, 2));
168
+ else console.log(out.trim().split('\n').pop() || '[]');
169
+ } catch {
170
+ console.log(out.trim() || '[]');
171
+ }
172
+ }
173
+ process.exit(0);
174
+ }
175
+
176
+ if (!parsed.tool) {
177
+ console.error('[lemma-call] Missing tool name. Try --help');
178
+ process.exit(2);
179
+ }
180
+
181
+ let argsObj = parsed.jsonObj;
182
+ // If no args from CLI, try stdin
183
+ if (!argsObj) {
184
+ const stdinData = await readStdin();
185
+ if (stdinData && typeof stdinData === 'object') argsObj = stdinData;
186
+ else if (typeof stdinData === 'string' && stdinData) {
187
+ try { argsObj = JSON.parse(stdinData); } catch { argsObj = { query: stdinData }; }
188
+ }
189
+ }
190
+ if (!argsObj) argsObj = {};
191
+
192
+ // MCP handshake: initialize → initialized → tools/call (required by SDK)
193
+ const initReq = JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2024-11-05', capabilities: {}, clientInfo: { name: 'lemma-call', version: '1.0.0' } } }) + '\n';
194
+ const initialized = JSON.stringify({ jsonrpc: '2.0', method: 'notifications/initialized' }) + '\n';
195
+ const request = JSON.stringify({
196
+ jsonrpc: '2.0',
197
+ id: 2,
198
+ method: 'tools/call',
199
+ params: { name: parsed.tool, arguments: argsObj }
200
+ }) + '\n';
201
+
202
+ const child = spawn(process.execPath, [mcpPath], { stdio: ['pipe', 'pipe', 'pipe'] });
203
+ let stdout = '';
204
+ let stderr = '';
205
+ child.stdout.on('data', d => stdout += d.toString());
206
+ child.stderr.on('data', d => stderr += d.toString());
207
+ child.stdin.write(initReq);
208
+ child.stdin.write(initialized);
209
+ child.stdin.write(request);
210
+ // Keep stdin open briefly for server to process; MCP SDK buffers responses
211
+ await new Promise(r => setTimeout(r, 500));
212
+ child.stdin.end();
213
+ // Wait for response with timeout
214
+ const exitCode = await Promise.race([
215
+ new Promise(resolve => child.on('close', resolve)),
216
+ new Promise(resolve => setTimeout(() => { try { child.kill(); } catch {}; resolve(0); }, 5000))
217
+ ]);
218
+
219
+ // MCP server returns JSON-RPC with result.content[].text — find id:2 response
220
+ const lines = stdout.trim().split('\n').filter(Boolean);
221
+ let parsedRes = null;
222
+ for (const line of lines) {
223
+ try {
224
+ const j = JSON.parse(line);
225
+ if (j.id === 2) { parsedRes = j; break; }
226
+ } catch {}
227
+ }
228
+ if (!parsedRes) {
229
+ try { parsedRes = JSON.parse(lines[lines.length - 1] || ''); } catch {}
230
+ }
231
+
232
+ if (parsedRes && parsedRes.result) {
233
+ // Pretty-print the tool result for Muse to read easily
234
+ const content = parsedRes.result.content;
235
+ if (Array.isArray(content)) {
236
+ for (const c of content) {
237
+ if (c.text) {
238
+ // Try to pretty-print if text is JSON
239
+ try {
240
+ const j = JSON.parse(c.text);
241
+ console.log(JSON.stringify(j, null, 2));
242
+ } catch {
243
+ console.log(c.text);
244
+ }
245
+ } else {
246
+ console.log(JSON.stringify(c, null, 2));
247
+ }
248
+ }
249
+ } else {
250
+ console.log(JSON.stringify(parsedRes.result, null, 2));
251
+ }
252
+ // Propagate isError as exit code
253
+ if (parsedRes.result.isError) process.exit(1);
254
+ process.exit(0);
255
+ }
256
+
257
+ if (parsedRes && parsedRes.error) {
258
+ console.error(`[lemma-call] MCP error: ${parsedRes.error.message || JSON.stringify(parsedRes.error)}`);
259
+ if (stderr.trim()) console.error(stderr.trim());
260
+ process.exit(1);
261
+ }
262
+
263
+ // Fallback: dump raw output
264
+ if (stdout.trim()) console.log(stdout.trim());
265
+ if (stderr.trim()) console.error(stderr.trim());
266
+ process.exit(exitCode || 0);
267
+ }
268
+
269
+ main().catch(e => { console.error('[lemma-call]', e.message); process.exit(1); });