@nxuss/lemma 1.37.0 → 1.39.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 +9 -6
- package/bin/brain-ingest.js +86 -27
- package/bin/doctor.js +31 -4
- package/bin/init.js +98 -60
- package/dashboard/dist/assets/index-DNTQXLER.css +1 -0
- package/dashboard/dist/assets/index-DzL_Zu3m.js +452 -0
- package/dashboard/dist/index.html +2 -2
- package/dist/cjs/cli/gitHooks.d.ts +9 -2
- package/dist/cjs/cli/gitHooks.d.ts.map +1 -1
- package/dist/cjs/cli/gitHooks.js +31 -4
- package/dist/cjs/cli/gitHooks.js.map +1 -1
- package/dist/cjs/cli/hostHooks.d.ts +13 -1
- package/dist/cjs/cli/hostHooks.d.ts.map +1 -1
- package/dist/cjs/cli/hostHooks.js +34 -4
- package/dist/cjs/cli/hostHooks.js.map +1 -1
- package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/cjs/cli/lemma-proxy.js +42 -5
- package/dist/cjs/cli/lemma-proxy.js.map +1 -1
- package/dist/cjs/infra/analyzers/index.d.ts +0 -2
- package/dist/cjs/infra/analyzers/index.d.ts.map +1 -1
- package/dist/cjs/infra/analyzers/index.js +1 -6
- package/dist/cjs/infra/analyzers/index.js.map +1 -1
- package/dist/cjs/infra/cli.d.ts +4 -0
- package/dist/cjs/infra/cli.d.ts.map +1 -1
- package/dist/cjs/infra/cli.js +6 -199
- package/dist/cjs/infra/cli.js.map +1 -1
- package/dist/cjs/infra/index.d.ts +1 -3
- package/dist/cjs/infra/index.d.ts.map +1 -1
- package/dist/cjs/infra/index.js +1 -16
- package/dist/cjs/infra/index.js.map +1 -1
- package/dist/cjs/infra/mcp-tools.d.ts.map +1 -1
- package/dist/cjs/infra/mcp-tools.js +8 -453
- package/dist/cjs/infra/mcp-tools.js.map +1 -1
- package/dist/cjs/infra/types.d.ts +0 -101
- package/dist/cjs/infra/types.d.ts.map +1 -1
- package/dist/cjs/infra/types.js +2 -1
- package/dist/cjs/infra/types.js.map +1 -1
- package/dist/cjs/mcp/index.js +33 -10
- package/dist/cjs/mcp/index.js.map +1 -1
- package/dist/cjs/mcp/prompts.d.ts +1 -1
- package/dist/cjs/mcp/prompts.d.ts.map +1 -1
- package/dist/cjs/mcp/prompts.js +8 -21
- package/dist/cjs/mcp/prompts.js.map +1 -1
- package/dist/cjs/mcp/tool-profiles.d.ts +8 -3
- package/dist/cjs/mcp/tool-profiles.d.ts.map +1 -1
- package/dist/cjs/mcp/tool-profiles.js +25 -54
- package/dist/cjs/mcp/tool-profiles.js.map +1 -1
- package/dist/cjs/mcp/tools/memory.d.ts +8 -0
- package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
- package/dist/cjs/mcp/tools/memory.js +154 -125
- package/dist/cjs/mcp/tools/memory.js.map +1 -1
- package/dist/cjs/mcp/tools.d.ts.map +1 -1
- package/dist/cjs/mcp/tools.js +11 -6
- package/dist/cjs/mcp/tools.js.map +1 -1
- package/dist/cjs/mcp/workspaceShared.d.ts.map +1 -1
- package/dist/cjs/mcp/workspaceShared.js +13 -12
- package/dist/cjs/mcp/workspaceShared.js.map +1 -1
- package/dist/cjs/proxy/ProjectRegistry.d.ts +44 -0
- package/dist/cjs/proxy/ProjectRegistry.d.ts.map +1 -1
- package/dist/cjs/proxy/ProjectRegistry.js +92 -3
- package/dist/cjs/proxy/ProjectRegistry.js.map +1 -1
- package/dist/cjs/subconscious/HostRecall.d.ts +36 -3
- package/dist/cjs/subconscious/HostRecall.d.ts.map +1 -1
- package/dist/cjs/subconscious/HostRecall.js +164 -37
- package/dist/cjs/subconscious/HostRecall.js.map +1 -1
- package/dist/cjs/subconscious/NarrowEvidence.d.ts +47 -0
- package/dist/cjs/subconscious/NarrowEvidence.d.ts.map +1 -0
- package/dist/cjs/subconscious/NarrowEvidence.js +252 -0
- package/dist/cjs/subconscious/NarrowEvidence.js.map +1 -0
- package/dist/cjs/subconscious/TheBrainV2.d.ts +37 -0
- package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
- package/dist/cjs/subconscious/TheBrainV2.js +147 -15
- package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
- package/dist/cjs/subconscious/freshness/LocalFsResolver.d.ts.map +1 -1
- package/dist/cjs/subconscious/freshness/LocalFsResolver.js +17 -0
- package/dist/cjs/subconscious/freshness/LocalFsResolver.js.map +1 -1
- package/dist/cjs/subconscious/recallDigest.d.ts +42 -0
- package/dist/cjs/subconscious/recallDigest.d.ts.map +1 -0
- package/dist/cjs/subconscious/recallDigest.js +94 -0
- package/dist/cjs/subconscious/recallDigest.js.map +1 -0
- package/dist/cjs/utils/OtherLanguageSymbols.d.ts +31 -0
- package/dist/cjs/utils/OtherLanguageSymbols.d.ts.map +1 -0
- package/dist/cjs/utils/OtherLanguageSymbols.js +283 -0
- package/dist/cjs/utils/OtherLanguageSymbols.js.map +1 -0
- package/dist/cjs/utils/SavingsLedger.d.ts +27 -0
- package/dist/cjs/utils/SavingsLedger.d.ts.map +1 -1
- package/dist/cjs/utils/SavingsLedger.js +51 -0
- package/dist/cjs/utils/SavingsLedger.js.map +1 -1
- package/dist/cjs/utils/StoreDraft.d.ts +12 -0
- package/dist/cjs/utils/StoreDraft.d.ts.map +1 -1
- package/dist/cjs/utils/StoreDraft.js +53 -1
- package/dist/cjs/utils/StoreDraft.js.map +1 -1
- package/dist/cjs/utils/SymbolSurgicalContext.d.ts +2 -0
- package/dist/cjs/utils/SymbolSurgicalContext.d.ts.map +1 -1
- package/dist/cjs/utils/SymbolSurgicalContext.js +1 -0
- package/dist/cjs/utils/SymbolSurgicalContext.js.map +1 -1
- package/dist/cjs/utils/reportSavings.d.ts +17 -4
- package/dist/cjs/utils/reportSavings.d.ts.map +1 -1
- package/dist/cjs/utils/reportSavings.js +67 -22
- package/dist/cjs/utils/reportSavings.js.map +1 -1
- package/dist/esm/cli/gitHooks.d.ts +9 -2
- package/dist/esm/cli/gitHooks.d.ts.map +1 -1
- package/dist/esm/cli/gitHooks.js +31 -4
- package/dist/esm/cli/gitHooks.js.map +1 -1
- package/dist/esm/cli/hostHooks.d.ts +13 -1
- package/dist/esm/cli/hostHooks.d.ts.map +1 -1
- package/dist/esm/cli/hostHooks.js +32 -3
- package/dist/esm/cli/hostHooks.js.map +1 -1
- package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/esm/cli/lemma-proxy.js +42 -5
- package/dist/esm/cli/lemma-proxy.js.map +1 -1
- package/dist/esm/infra/analyzers/index.d.ts +0 -2
- package/dist/esm/infra/analyzers/index.d.ts.map +1 -1
- package/dist/esm/infra/analyzers/index.js +0 -2
- package/dist/esm/infra/analyzers/index.js.map +1 -1
- package/dist/esm/infra/cli.d.ts +4 -0
- package/dist/esm/infra/cli.d.ts.map +1 -1
- package/dist/esm/infra/cli.js +6 -199
- package/dist/esm/infra/cli.js.map +1 -1
- package/dist/esm/infra/index.d.ts +1 -3
- package/dist/esm/infra/index.d.ts.map +1 -1
- package/dist/esm/infra/index.js +1 -3
- package/dist/esm/infra/index.js.map +1 -1
- package/dist/esm/infra/mcp-tools.d.ts.map +1 -1
- package/dist/esm/infra/mcp-tools.js +9 -454
- package/dist/esm/infra/mcp-tools.js.map +1 -1
- package/dist/esm/infra/types.d.ts +0 -101
- package/dist/esm/infra/types.d.ts.map +1 -1
- package/dist/esm/infra/types.js +2 -1
- package/dist/esm/infra/types.js.map +1 -1
- package/dist/esm/mcp/index.js +33 -10
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/mcp/prompts.d.ts +1 -1
- package/dist/esm/mcp/prompts.d.ts.map +1 -1
- package/dist/esm/mcp/prompts.js +8 -21
- package/dist/esm/mcp/prompts.js.map +1 -1
- package/dist/esm/mcp/tool-profiles.d.ts +8 -3
- package/dist/esm/mcp/tool-profiles.d.ts.map +1 -1
- package/dist/esm/mcp/tool-profiles.js +25 -54
- package/dist/esm/mcp/tool-profiles.js.map +1 -1
- package/dist/esm/mcp/tools/memory.d.ts +8 -0
- package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
- package/dist/esm/mcp/tools/memory.js +156 -128
- package/dist/esm/mcp/tools/memory.js.map +1 -1
- package/dist/esm/mcp/tools.d.ts.map +1 -1
- package/dist/esm/mcp/tools.js +12 -7
- package/dist/esm/mcp/tools.js.map +1 -1
- package/dist/esm/mcp/workspaceShared.d.ts.map +1 -1
- package/dist/esm/mcp/workspaceShared.js +13 -12
- package/dist/esm/mcp/workspaceShared.js.map +1 -1
- package/dist/esm/proxy/ProjectRegistry.d.ts +44 -0
- package/dist/esm/proxy/ProjectRegistry.d.ts.map +1 -1
- package/dist/esm/proxy/ProjectRegistry.js +91 -2
- package/dist/esm/proxy/ProjectRegistry.js.map +1 -1
- package/dist/esm/subconscious/HostRecall.d.ts +36 -3
- package/dist/esm/subconscious/HostRecall.d.ts.map +1 -1
- package/dist/esm/subconscious/HostRecall.js +159 -36
- package/dist/esm/subconscious/HostRecall.js.map +1 -1
- package/dist/esm/subconscious/NarrowEvidence.d.ts +47 -0
- package/dist/esm/subconscious/NarrowEvidence.d.ts.map +1 -0
- package/dist/esm/subconscious/NarrowEvidence.js +211 -0
- package/dist/esm/subconscious/NarrowEvidence.js.map +1 -0
- package/dist/esm/subconscious/TheBrainV2.d.ts +37 -0
- package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
- package/dist/esm/subconscious/TheBrainV2.js +146 -14
- package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
- package/dist/esm/subconscious/freshness/LocalFsResolver.d.ts.map +1 -1
- package/dist/esm/subconscious/freshness/LocalFsResolver.js +17 -0
- package/dist/esm/subconscious/freshness/LocalFsResolver.js.map +1 -1
- package/dist/esm/subconscious/recallDigest.d.ts +42 -0
- package/dist/esm/subconscious/recallDigest.d.ts.map +1 -0
- package/dist/esm/subconscious/recallDigest.js +87 -0
- package/dist/esm/subconscious/recallDigest.js.map +1 -0
- package/dist/esm/utils/OtherLanguageSymbols.d.ts +31 -0
- package/dist/esm/utils/OtherLanguageSymbols.d.ts.map +1 -0
- package/dist/esm/utils/OtherLanguageSymbols.js +275 -0
- package/dist/esm/utils/OtherLanguageSymbols.js.map +1 -0
- package/dist/esm/utils/SavingsLedger.d.ts +27 -0
- package/dist/esm/utils/SavingsLedger.d.ts.map +1 -1
- package/dist/esm/utils/SavingsLedger.js +51 -0
- package/dist/esm/utils/SavingsLedger.js.map +1 -1
- package/dist/esm/utils/StoreDraft.d.ts +12 -0
- package/dist/esm/utils/StoreDraft.d.ts.map +1 -1
- package/dist/esm/utils/StoreDraft.js +52 -1
- package/dist/esm/utils/StoreDraft.js.map +1 -1
- package/dist/esm/utils/SymbolSurgicalContext.d.ts +2 -0
- package/dist/esm/utils/SymbolSurgicalContext.d.ts.map +1 -1
- package/dist/esm/utils/SymbolSurgicalContext.js +1 -1
- package/dist/esm/utils/SymbolSurgicalContext.js.map +1 -1
- package/dist/esm/utils/reportSavings.d.ts +17 -4
- package/dist/esm/utils/reportSavings.d.ts.map +1 -1
- package/dist/esm/utils/reportSavings.js +65 -22
- package/dist/esm/utils/reportSavings.js.map +1 -1
- package/package.json +2 -1
- package/dashboard/dist/assets/index-BoeQau6n.css +0 -1
- package/dashboard/dist/assets/index-Clf3qR64.js +0 -451
- package/dist/cjs/infra/analyzers/DriftDetector.d.ts +0 -4
- package/dist/cjs/infra/analyzers/DriftDetector.d.ts.map +0 -1
- package/dist/cjs/infra/analyzers/DriftDetector.js +0 -88
- package/dist/cjs/infra/analyzers/DriftDetector.js.map +0 -1
- package/dist/cjs/infra/analyzers/InfraAnalyzer.d.ts +0 -3
- package/dist/cjs/infra/analyzers/InfraAnalyzer.d.ts.map +0 -1
- package/dist/cjs/infra/analyzers/InfraAnalyzer.js +0 -73
- package/dist/cjs/infra/analyzers/InfraAnalyzer.js.map +0 -1
- package/dist/cjs/infra/config.d.ts +0 -17
- package/dist/cjs/infra/config.d.ts.map +0 -1
- package/dist/cjs/infra/config.js +0 -111
- package/dist/cjs/infra/config.js.map +0 -1
- package/dist/cjs/infra/errorCause.d.ts +0 -36
- package/dist/cjs/infra/errorCause.d.ts.map +0 -1
- package/dist/cjs/infra/errorCause.js +0 -143
- package/dist/cjs/infra/errorCause.js.map +0 -1
- package/dist/cjs/infra/providers/InfraProvider.d.ts +0 -9
- package/dist/cjs/infra/providers/InfraProvider.d.ts.map +0 -1
- package/dist/cjs/infra/providers/InfraProvider.js +0 -3
- package/dist/cjs/infra/providers/InfraProvider.js.map +0 -1
- package/dist/cjs/infra/providers/JenkinsProvider.d.ts +0 -16
- package/dist/cjs/infra/providers/JenkinsProvider.d.ts.map +0 -1
- package/dist/cjs/infra/providers/JenkinsProvider.js +0 -193
- package/dist/cjs/infra/providers/JenkinsProvider.js.map +0 -1
- package/dist/cjs/infra/providers/OKDProvider.d.ts +0 -24
- package/dist/cjs/infra/providers/OKDProvider.d.ts.map +0 -1
- package/dist/cjs/infra/providers/OKDProvider.js +0 -296
- package/dist/cjs/infra/providers/OKDProvider.js.map +0 -1
- package/dist/cjs/infra/providers/TerraformProvider.d.ts +0 -17
- package/dist/cjs/infra/providers/TerraformProvider.d.ts.map +0 -1
- package/dist/cjs/infra/providers/TerraformProvider.js +0 -111
- package/dist/cjs/infra/providers/TerraformProvider.js.map +0 -1
- package/dist/cjs/infra/providers/index.d.ts +0 -9
- package/dist/cjs/infra/providers/index.d.ts.map +0 -1
- package/dist/cjs/infra/providers/index.js +0 -34
- package/dist/cjs/infra/providers/index.js.map +0 -1
- package/dist/cjs/infra/templates/jenkins/index.d.ts +0 -15
- package/dist/cjs/infra/templates/jenkins/index.d.ts.map +0 -1
- package/dist/cjs/infra/templates/jenkins/index.js +0 -128
- package/dist/cjs/infra/templates/jenkins/index.js.map +0 -1
- package/dist/cjs/infra/templates/okd/index.d.ts +0 -31
- package/dist/cjs/infra/templates/okd/index.d.ts.map +0 -1
- package/dist/cjs/infra/templates/okd/index.js +0 -149
- package/dist/cjs/infra/templates/okd/index.js.map +0 -1
- package/dist/esm/infra/analyzers/DriftDetector.d.ts +0 -4
- package/dist/esm/infra/analyzers/DriftDetector.d.ts.map +0 -1
- package/dist/esm/infra/analyzers/DriftDetector.js +0 -84
- package/dist/esm/infra/analyzers/DriftDetector.js.map +0 -1
- package/dist/esm/infra/analyzers/InfraAnalyzer.d.ts +0 -3
- package/dist/esm/infra/analyzers/InfraAnalyzer.d.ts.map +0 -1
- package/dist/esm/infra/analyzers/InfraAnalyzer.js +0 -70
- package/dist/esm/infra/analyzers/InfraAnalyzer.js.map +0 -1
- package/dist/esm/infra/config.d.ts +0 -17
- package/dist/esm/infra/config.d.ts.map +0 -1
- package/dist/esm/infra/config.js +0 -101
- package/dist/esm/infra/config.js.map +0 -1
- package/dist/esm/infra/errorCause.d.ts +0 -36
- package/dist/esm/infra/errorCause.d.ts.map +0 -1
- package/dist/esm/infra/errorCause.js +0 -138
- package/dist/esm/infra/errorCause.js.map +0 -1
- package/dist/esm/infra/providers/InfraProvider.d.ts +0 -9
- package/dist/esm/infra/providers/InfraProvider.d.ts.map +0 -1
- package/dist/esm/infra/providers/InfraProvider.js +0 -2
- package/dist/esm/infra/providers/InfraProvider.js.map +0 -1
- package/dist/esm/infra/providers/JenkinsProvider.d.ts +0 -16
- package/dist/esm/infra/providers/JenkinsProvider.d.ts.map +0 -1
- package/dist/esm/infra/providers/JenkinsProvider.js +0 -186
- package/dist/esm/infra/providers/JenkinsProvider.js.map +0 -1
- package/dist/esm/infra/providers/OKDProvider.d.ts +0 -24
- package/dist/esm/infra/providers/OKDProvider.d.ts.map +0 -1
- package/dist/esm/infra/providers/OKDProvider.js +0 -292
- package/dist/esm/infra/providers/OKDProvider.js.map +0 -1
- package/dist/esm/infra/providers/TerraformProvider.d.ts +0 -17
- package/dist/esm/infra/providers/TerraformProvider.d.ts.map +0 -1
- package/dist/esm/infra/providers/TerraformProvider.js +0 -107
- package/dist/esm/infra/providers/TerraformProvider.js.map +0 -1
- package/dist/esm/infra/providers/index.d.ts +0 -9
- package/dist/esm/infra/providers/index.d.ts.map +0 -1
- package/dist/esm/infra/providers/index.js +0 -27
- package/dist/esm/infra/providers/index.js.map +0 -1
- package/dist/esm/infra/templates/jenkins/index.d.ts +0 -15
- package/dist/esm/infra/templates/jenkins/index.d.ts.map +0 -1
- package/dist/esm/infra/templates/jenkins/index.js +0 -124
- package/dist/esm/infra/templates/jenkins/index.js.map +0 -1
- package/dist/esm/infra/templates/okd/index.d.ts +0 -31
- package/dist/esm/infra/templates/okd/index.d.ts.map +0 -1
- package/dist/esm/infra/templates/okd/index.js +0 -142
- package/dist/esm/infra/templates/okd/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@nxuss/lemma)
|
|
4
4
|
[](https://github.com/Nxusbets/lemma/blob/main/LICENSE)
|
|
5
|
-
[](https://github.com/Nxusbets/lemma)
|
|
6
6
|
[](https://github.com/Nxusbets/lemma)
|
|
7
7
|
|
|
8
8
|
**A memory your AI agent can verify, and a context window that only holds what matters.**
|
|
@@ -60,8 +60,7 @@ pretending (`capability_matrix`).
|
|
|
60
60
|
|
|
61
61
|
## Free vs Pro
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
infrastructure tools (Jenkins, OKD/OpenShift, Terraform). Pro adds writing and patching,
|
|
63
|
+
41 of the 91 tools are free, including all memory, upkeep and export tools. Pro adds writing and patching,
|
|
65
64
|
`search_workspace`, `run_workspace_command`, static analysis, PR review and auto-heal.
|
|
66
65
|
|
|
67
66
|
| | Free | Pro |
|
|
@@ -70,7 +69,7 @@ infrastructure tools (Jenkins, OKD/OpenShift, Terraform). Pro adds writing and p
|
|
|
70
69
|
| Context | `read_workspace_file`, `scrub_privacy`, `token_budget`, `token_receipt`, `auto_context_bundle` | `get_ast_hologram`, `smart_file_slice`, `get_symbol_surgical_context` |
|
|
71
70
|
| Workspace | — | `apply_workspace_patch`, `write_workspace_file`, `run_workspace_command`, `validate_patch_sandbox`, `surgical_ast_insert` |
|
|
72
71
|
| Analysis & review | `type_coverage_report`, `git_blame_heat` | `depgraph`, `entropy_score`, `refactor`, `review_diff`, `review_pr`, `test_oracle` |
|
|
73
|
-
|
|
|
72
|
+
| Monolith analysis | `infra_analyze_monolith`, `infra_suggest_split` (not advertised; via `lemma_toolbox`) | — |
|
|
74
73
|
|
|
75
74
|
Without a license, Pro tools aren't advertised to the model at all. Full list:
|
|
76
75
|
`lemma_toolbox { "action": "list" }`. Get Pro: `lemma activate <key>` →
|
|
@@ -87,8 +86,12 @@ Without a license, Pro tools aren't advertised to the model at all. Full list:
|
|
|
87
86
|
| Claude Desktop / any MCP client | `{ "command": "npx", "args": ["-y", "@nxuss/lemma", "mcp"] }` |
|
|
88
87
|
|
|
89
88
|
`lemma init` also installs the hooks that feed the Brain (git `post-commit` / `post-merge` /
|
|
90
|
-
`post-checkout`, and post-tool hooks for Claude Code, Codex, Cursor and OpenCode).
|
|
91
|
-
|
|
89
|
+
`post-checkout`, and post-tool hooks for Claude Code, Codex, Cursor and OpenCode). In Claude Code
|
|
90
|
+
it adds a `SessionStart` briefing and a prompt-time recall too, and pre-approves the read and
|
|
91
|
+
memory tools so using them never costs a permission prompt. Existing hooks are kept; `--no-hooks`
|
|
92
|
+
skips them. An install from an older version gets the missing Claude Code hooks the next time the
|
|
93
|
+
MCP server starts; re-run `lemma init` after upgrading to refresh the agent rules. Health check:
|
|
94
|
+
`lemma doctor`.
|
|
92
95
|
|
|
93
96
|
### CLI
|
|
94
97
|
|
package/bin/brain-ingest.js
CHANGED
|
@@ -4,16 +4,16 @@
|
|
|
4
4
|
/**
|
|
5
5
|
* Feeds The Brain from sources the model never has to remember to store manually.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Commit ingestion is opt-in (`--commits`). It used to run on every commit from a post-commit
|
|
8
|
+
* hook, and on Lemma's own repo it made 295 of 339 memories — a copy of `git log`, recalled
|
|
9
|
+
* twice in total, that crowded out the memories written on purpose. Hooks an older `lemma init`
|
|
10
|
+
* installed still call this with no flags; that is now a no-op for commits.
|
|
9
11
|
*
|
|
10
|
-
*
|
|
12
|
+
* With `--commits` it's an incremental catch-up: a marker file under .lemma/session/ tracks the
|
|
13
|
+
* last commit ingested, so repeated runs never double-store. `--max N` only matters the first
|
|
14
|
+
* time there is no marker yet. `--no-commits` is accepted and ignored (older hooks pass it).
|
|
11
15
|
*
|
|
12
|
-
*
|
|
13
|
-
* last commit ingested, so running this after every commit or by hand both take the same path
|
|
14
|
-
* and never double-store. `--max N` only matters the first time there is no marker yet.
|
|
15
|
-
*
|
|
16
|
-
* Usage: lemma-brain-ingest [projectRoot] [--max N] [--changelog] [--no-commits] [--team-pull]
|
|
16
|
+
* Usage: lemma-brain-ingest [projectRoot] [--commits [--max N]] [--changelog] [--team-pull]
|
|
17
17
|
* lemma-brain-ingest --hook-result [--host=claude|codex|cursor|opencode] < payload.json
|
|
18
18
|
* lemma-brain-ingest --prompt-submit < payload.json
|
|
19
19
|
*
|
|
@@ -49,12 +49,27 @@ function readStdin() {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
// Tell the dashboard which memories a note offered (see reportRecall). Awaited: this process
|
|
53
|
+
// exits as soon as it has answered the host, and an unfinished request would die with it.
|
|
54
|
+
async function reportOffered(dist, root, notes) {
|
|
55
|
+
try {
|
|
56
|
+
const { reportRecall } = require(path.join(dist, 'utils', 'reportSavings.js'));
|
|
57
|
+
const { repoRoot } = require(path.join(dist, 'subconscious', 'TeamBrain.js'));
|
|
58
|
+
const projectPath = repoRoot(root || process.cwd());
|
|
59
|
+
await Promise.all(
|
|
60
|
+
notes.filter((n) => n && n.offered.length > 0).map((n) => reportRecall({ projectPath, trigger: n.trigger, memoryIds: n.offered }))
|
|
61
|
+
);
|
|
62
|
+
} catch {
|
|
63
|
+
// Reporting is bookkeeping; the note itself already went to the host.
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function hookResult(args) {
|
|
53
68
|
const dist = path.join(__dirname, '..', 'dist', 'cjs');
|
|
54
|
-
let recordHookPayload,
|
|
69
|
+
let recordHookPayload, hookRecall, normalizeHostPayload, formatHostOutput, parseHost;
|
|
55
70
|
try {
|
|
56
71
|
({ recordHookPayload } = require(path.join(dist, 'utils', 'FixCapture.js')));
|
|
57
|
-
({
|
|
72
|
+
({ hookRecall } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
|
|
58
73
|
({ normalizeHostPayload, formatHostOutput, parseHost } = require(path.join(dist, 'subconscious', 'HostAdapters.js')));
|
|
59
74
|
} catch {
|
|
60
75
|
return; // no build — a hook must stay silent and harmless
|
|
@@ -68,23 +83,30 @@ function hookResult(args) {
|
|
|
68
83
|
return;
|
|
69
84
|
}
|
|
70
85
|
const notes = [];
|
|
86
|
+
const recalled = [];
|
|
87
|
+
let root;
|
|
71
88
|
for (const payload of normalizeHostPayload(host, raw)) {
|
|
72
89
|
try {
|
|
73
90
|
const res = recordHookPayload(payload, payload.cwd);
|
|
74
91
|
if (res && res.captured) console.error(res.note.trim());
|
|
75
92
|
} catch { /* capture failing must not cost the recall below */ }
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
93
|
+
const recall = hookRecall(payload, payload.cwd);
|
|
94
|
+
if (recall && !notes.includes(recall.text)) {
|
|
95
|
+
notes.push(recall.text);
|
|
96
|
+
recalled.push(recall);
|
|
97
|
+
root = root || payload.cwd;
|
|
98
|
+
}
|
|
78
99
|
}
|
|
79
100
|
const out = formatHostOutput(host, notes.join('\n'));
|
|
80
101
|
if (out) process.stdout.write(out);
|
|
102
|
+
await reportOffered(dist, root, recalled);
|
|
81
103
|
}
|
|
82
104
|
|
|
83
|
-
function promptSubmit() {
|
|
105
|
+
async function promptSubmit() {
|
|
84
106
|
const dist = path.join(__dirname, '..', 'dist', 'cjs');
|
|
85
|
-
let
|
|
107
|
+
let promptRecall, formatHostOutput;
|
|
86
108
|
try {
|
|
87
|
-
({
|
|
109
|
+
({ promptRecall } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
|
|
88
110
|
({ formatHostOutput } = require(path.join(dist, 'subconscious', 'HostAdapters.js')));
|
|
89
111
|
} catch {
|
|
90
112
|
return; // no build — a hook must stay silent and harmless
|
|
@@ -95,18 +117,53 @@ function promptSubmit() {
|
|
|
95
117
|
} catch {
|
|
96
118
|
return;
|
|
97
119
|
}
|
|
98
|
-
const
|
|
120
|
+
const recall = promptRecall(payload, payload && payload.cwd, undefined, { mcpEntry: path.join(dist, 'mcp', 'index.js') });
|
|
121
|
+
const out = formatHostOutput('claude', recall ? recall.text : '', 'UserPromptSubmit');
|
|
122
|
+
if (out) process.stdout.write(out);
|
|
123
|
+
await reportOffered(dist, payload && payload.cwd, [recall]);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// SessionStart hook (Claude Code): the Brain's briefing and the Lemma playbook, in context
|
|
127
|
+
// before the first prompt — no tool call for the agent to remember or skip.
|
|
128
|
+
async function sessionStart() {
|
|
129
|
+
const dist = path.join(__dirname, '..', 'dist', 'cjs');
|
|
130
|
+
let sessionRecall, formatHostOutput;
|
|
131
|
+
try {
|
|
132
|
+
({ sessionRecall } = require(path.join(dist, 'subconscious', 'HostRecall.js')));
|
|
133
|
+
({ formatHostOutput } = require(path.join(dist, 'subconscious', 'HostAdapters.js')));
|
|
134
|
+
} catch {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
let payload = {};
|
|
138
|
+
try {
|
|
139
|
+
payload = JSON.parse(readStdin()) || {};
|
|
140
|
+
} catch {
|
|
141
|
+
// No payload is fine: the briefing only needs a directory.
|
|
142
|
+
}
|
|
143
|
+
// Work that landed since the last session began becomes a "store what you learned" reminder
|
|
144
|
+
// for the first prompt — no SessionEnd hook needed, which no installer wires up.
|
|
145
|
+
try {
|
|
146
|
+
const { draftSinceLastSession } = require(path.join(dist, 'utils', 'StoreDraft.js'));
|
|
147
|
+
const { repoRoot } = require(path.join(dist, 'subconscious', 'TeamBrain.js'));
|
|
148
|
+
draftSinceLastSession(repoRoot(payload.cwd || process.cwd()));
|
|
149
|
+
} catch {
|
|
150
|
+
// the reminder is a courtesy; the briefing must still go out
|
|
151
|
+
}
|
|
152
|
+
const recall = sessionRecall(payload, payload.cwd);
|
|
153
|
+
const out = formatHostOutput('claude', recall ? recall.text : '', 'SessionStart');
|
|
99
154
|
if (out) process.stdout.write(out);
|
|
155
|
+
await reportOffered(dist, payload.cwd, [recall]);
|
|
100
156
|
}
|
|
101
157
|
|
|
102
|
-
function main() {
|
|
158
|
+
async function main() {
|
|
103
159
|
const args = process.argv.slice(2);
|
|
160
|
+
if (args.includes('--session-start')) return sessionStart();
|
|
104
161
|
if (args.includes('--prompt-submit')) return promptSubmit();
|
|
105
162
|
if (args.includes('--hook-result')) return hookResult(args);
|
|
106
163
|
const maxIndex = args.indexOf('--max');
|
|
107
164
|
const maxCommits = maxIndex >= 0 ? parseInt(args[maxIndex + 1], 10) : undefined;
|
|
108
165
|
const includeChangelog = args.includes('--changelog');
|
|
109
|
-
const includeCommits =
|
|
166
|
+
const includeCommits = args.includes('--commits');
|
|
110
167
|
const teamPull = args.includes('--team-pull');
|
|
111
168
|
const positional = args.filter((a, i) => !a.startsWith("--") && (maxIndex < 0 || i !== maxIndex + 1));
|
|
112
169
|
const projectRoot = path.resolve(positional[0] || process.cwd());
|
|
@@ -156,11 +213,13 @@ function flushBrain() {
|
|
|
156
213
|
}
|
|
157
214
|
}
|
|
158
215
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
216
|
+
(async () => {
|
|
217
|
+
try {
|
|
218
|
+
await main();
|
|
219
|
+
} catch (err) {
|
|
220
|
+
// A hook that fails must never be the reason a commit or session goes bad.
|
|
221
|
+
console.error('[lemma-brain-ingest] Skipped:', err && err.message);
|
|
222
|
+
}
|
|
223
|
+
flushBrain();
|
|
224
|
+
process.exit(0);
|
|
225
|
+
})();
|
package/bin/doctor.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Lemma doctor — verifies the Lemma wiring on this machine / project:
|
|
6
|
-
* wrapper, project skill, user skill (muse),
|
|
6
|
+
* wrapper, project skill, user skill (muse), AGENTS.md block, and Claude Code hooks/permissions.
|
|
7
7
|
*
|
|
8
8
|
* Usage: `lemma doctor` (exit 0 = usable, exit 1 = wrapper broken).
|
|
9
9
|
*/
|
|
@@ -111,10 +111,37 @@ async function main() {
|
|
|
111
111
|
const agentsPath = path.join(cwd, 'AGENTS.md');
|
|
112
112
|
if (!fs.existsSync(agentsPath) || !fs.readFileSync(agentsPath, 'utf8').includes('@nxuss/lemma')) {
|
|
113
113
|
warn('no Lemma block in ./AGENTS.md — run `lemma init`');
|
|
114
|
-
} else if (fs.readFileSync(agentsPath, 'utf8').includes('
|
|
115
|
-
ok('AGENTS.md block current (
|
|
114
|
+
} else if (fs.readFileSync(agentsPath, 'utf8').includes('## Triggers')) {
|
|
115
|
+
ok('AGENTS.md block current (trigger-based rules)');
|
|
116
116
|
} else {
|
|
117
|
-
warn('AGENTS.md block is stale (pre
|
|
117
|
+
warn('AGENTS.md block is stale (pre trigger rules) — re-run `lemma init`');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 5. Claude Code hooks + permissions — what makes the Brain speak without being asked.
|
|
121
|
+
const claudeLocal = path.join(cwd, '.claude', 'settings.local.json');
|
|
122
|
+
let claudeSettings = null;
|
|
123
|
+
try {
|
|
124
|
+
claudeSettings = JSON.parse(fs.readFileSync(claudeLocal, 'utf8'));
|
|
125
|
+
} catch {
|
|
126
|
+
// missing or unreadable — reported below
|
|
127
|
+
}
|
|
128
|
+
if (!claudeSettings) {
|
|
129
|
+
warn('no .claude/settings.local.json — run `lemma init` for Claude Code hooks');
|
|
130
|
+
} else {
|
|
131
|
+
const hooksText = JSON.stringify(claudeSettings.hooks || {});
|
|
132
|
+
const missing = [
|
|
133
|
+
['PostToolUse', 'lemma-brain-ingest --hook-result'],
|
|
134
|
+
['UserPromptSubmit', 'lemma-brain-ingest --prompt-submit'],
|
|
135
|
+
['SessionStart', 'lemma-brain-ingest --session-start'],
|
|
136
|
+
].filter(([, mark]) => !hooksText.includes(mark)).map(([event]) => event);
|
|
137
|
+
if (missing.length === 0) ok('Claude Code hooks current (PostToolUse, UserPromptSubmit, SessionStart)');
|
|
138
|
+
else warn(`Claude Code hooks missing: ${missing.join(', ')} — re-run \`lemma init\` (or restart the MCP server: it repairs an existing install)`);
|
|
139
|
+
|
|
140
|
+
const allow = (claudeSettings.permissions && claudeSettings.permissions.allow) || [];
|
|
141
|
+
const core = ['search_memory', 'get_memory', 'verify_memory', 'store_memory', 'update_memory', 'read_workspace_file', 'search_workspace'];
|
|
142
|
+
const unallowed = core.filter((t) => !allow.includes(`mcp__lemma__${t}`) && !allow.includes('mcp__lemma'));
|
|
143
|
+
if (unallowed.length === 0) ok('core Lemma tools pre-approved (no permission prompt)');
|
|
144
|
+
else warn(`core Lemma tools still prompt for permission: ${unallowed.join(', ')} — re-run \`lemma init\``);
|
|
118
145
|
}
|
|
119
146
|
|
|
120
147
|
process.stdout.write(`\n ${DIM}Brain: ~/.lemma-cache/lemma_brain.json · proxy: lemma-proxy.cjs status${RESET}\n\n`);
|
package/bin/init.js
CHANGED
|
@@ -260,17 +260,41 @@ function loadLemmaToolNames() {
|
|
|
260
260
|
}
|
|
261
261
|
|
|
262
262
|
const LEMMA_TOOL_NAMES = loadLemmaToolNames();
|
|
263
|
-
|
|
263
|
+
// Pre-approved in Claude Code: reading, searching and the Brain's lifecycle — local, and nothing
|
|
264
|
+
// a native Read/Grep couldn't already do. Tools that write code (apply_workspace_patch,
|
|
265
|
+
// surgical_ast_insert), run commands (run_workspace_command), delete (forget_memory) or
|
|
266
|
+
// dispatch arbitrary tools (lemma_toolbox) still ask.
|
|
267
|
+
const LEMMA_PREAPPROVED_TOOLS = [
|
|
268
|
+
'search_memory', 'get_memory', 'verify_memory', 'store_memory', 'update_memory', 'refresh_memory',
|
|
269
|
+
'downvote_memory', 'read_workspace_file', 'list_workspace_dir', 'search_workspace', 'smart_file_slice',
|
|
270
|
+
'get_ast_hologram', 'get_symbol_surgical_context', 'output_region', 'get_project_onboarding',
|
|
271
|
+
'state_hash_cache', 'smarter_cache', 'token_receipt', 'get_routing_advice',
|
|
272
|
+
].map((name) => `mcp__lemma__${name}`);
|
|
264
273
|
|
|
265
274
|
const CLAUDE_MD_CONTENT = `# Lemma MCP — Cómo usar las herramientas de este proyecto
|
|
266
275
|
|
|
267
|
-
Tienes conectado el servidor MCP \`lemma\`.
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
tokens sale más cara que los tokens que ahorra.
|
|
276
|
+
Tienes conectado el servidor MCP \`lemma\`. Lo que hace que las herramientas nativas no pueden
|
|
277
|
+
es **recordar entre sesiones**: el Brain guarda fixes y decisiones verificadas, y avisa cuando el
|
|
278
|
+
código del que dependen cambió. Ese valor solo existe si se consulta y se alimenta, así que estos
|
|
279
|
+
momentos no son opcionales:
|
|
272
280
|
|
|
273
|
-
##
|
|
281
|
+
## Disparadores — haz esto siempre
|
|
282
|
+
|
|
283
|
+
| Cuando… | Llama | Por qué no basta lo nativo |
|
|
284
|
+
|---|---|---|
|
|
285
|
+
| Vas a investigar un bug, un error o un "¿por qué X?" | \`mcp__lemma__search_memory\` con el texto del error o la pregunta | Puede que ya esté resuelto; \`grep\` no encuentra lo que se aprendió en otra sesión |
|
|
286
|
+
| Un aviso 🧠 de Lemma nombra memorias | \`mcp__lemma__get_memory\` de la primera | El aviso trae solo el titular; el cuerpo tiene los archivos y el porqué |
|
|
287
|
+
| Un fix quedó verificado (tests pasan, build ok, el usuario confirmó) | \`mcp__lemma__store_memory\` con \`filePaths\`: la causa raíz, la trampa o lo que no funcionó — no un resumen de qué cambió | Si no se guarda, la próxima sesión lo vuelve a investigar desde cero; un resumen de cambios ya está en git log y nadie lo vuelve a buscar |
|
|
288
|
+
| Una memoria resultó desactualizada o incorrecta | \`mcp__lemma__update_memory\` / \`forget_memory\` | Guardar otra al lado deja dos versiones y la búsqueda mezcla ambas |
|
|
289
|
+
| Vas a leer código que aún no ubicaste, o que puede tener secretos | \`mcp__lemma__search_workspace\` / \`read_workspace_file\` | Enmascaran API keys antes de que entren a tu contexto |
|
|
290
|
+
|
|
291
|
+
Si las tools de Lemma te llegan diferidas (solo el nombre), cárgalas en **una sola** llamada a
|
|
292
|
+
ToolSearch: \`select:mcp__lemma__search_memory,mcp__lemma__get_memory,mcp__lemma__verify_memory,mcp__lemma__store_memory,mcp__lemma__update_memory,mcp__lemma__read_workspace_file,mcp__lemma__search_workspace\`.
|
|
293
|
+
|
|
294
|
+
Fuera de esos momentos usa tu criterio: para un archivo chico que ya ubicaste, \`Read\` nativo
|
|
295
|
+
cuesta menos que el ida y vuelta, y para procesos, puertos o git Lemma no tiene nada que aportar.
|
|
296
|
+
|
|
297
|
+
## Referencia: qué tool para qué
|
|
274
298
|
|
|
275
299
|
| Tarea | Tool de Lemma | Por qué |
|
|
276
300
|
|---|---|---|
|
|
@@ -312,14 +336,13 @@ No le pidas que pegue archivos, logs o documentación que puedes obtener tú: ag
|
|
|
312
336
|
|
|
313
337
|
## Al iniciar en este proyecto
|
|
314
338
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
339
|
+
El hook \`SessionStart\` de Lemma ya te dio un resumen del Brain al arrancar (si no lo ves,
|
|
340
|
+
\`lemma doctor\` dice qué falta). Para más contexto: \`mcp__lemma__get_project_onboarding\`.
|
|
341
|
+
Lo que venga del Brain no es un hecho hasta verificarlo contra el estado actual del código.
|
|
318
342
|
|
|
319
|
-
## Al
|
|
343
|
+
## Al investigar un bug, además
|
|
320
344
|
|
|
321
|
-
|
|
322
|
-
2. \`lemma_toolbox\` → \`get_telepathic_hints\` con el archivo relevante para contexto de runtime.
|
|
345
|
+
\`lemma_toolbox\` → \`get_telepathic_hints\` con el archivo relevante para contexto de runtime.
|
|
323
346
|
|
|
324
347
|
## Una sola regla dura
|
|
325
348
|
|
|
@@ -342,6 +365,13 @@ function configureClaudeCode() {
|
|
|
342
365
|
const existingMd = fs.readFileSync(claudeMdPath, 'utf8');
|
|
343
366
|
if (!existingMd.includes('@nxuss/lemma')) {
|
|
344
367
|
fs.appendFileSync(claudeMdPath, '\n---\n\n' + CLAUDE_MD_CONTENT, 'utf8');
|
|
368
|
+
} else {
|
|
369
|
+
// Lemma's block — an older one ("úsalo cuando aporte algo real") or this one from an earlier
|
|
370
|
+
// release — is replaced in place with the current rules, keeping whatever the user wrote
|
|
371
|
+
// around it. Gating this on "already trigger-based" left every upgrade on stale rules.
|
|
372
|
+
const lemmaBlockRegex = /# Lemma MCP — Cómo usar[\s\S]*?\*Auto-generado por `lemma init` — @nxuss\/lemma\*/;
|
|
373
|
+
const updated = existingMd.replace(lemmaBlockRegex, CLAUDE_MD_CONTENT.trim());
|
|
374
|
+
if (updated !== existingMd) fs.writeFileSync(claudeMdPath, updated, 'utf8');
|
|
345
375
|
}
|
|
346
376
|
} else {
|
|
347
377
|
fs.writeFileSync(claudeMdPath, CLAUDE_MD_CONTENT, 'utf8');
|
|
@@ -363,11 +393,17 @@ function configureClaudeCode() {
|
|
|
363
393
|
);
|
|
364
394
|
settings.enableAllProjectMcpServers = true;
|
|
365
395
|
|
|
366
|
-
//
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
396
|
+
// Pre-approve the core tools in permissions.allow — the key Claude Code reads from settings
|
|
397
|
+
// files. Earlier versions wrote the whole catalog to a top-level `allowedTools`, which left the
|
|
398
|
+
// tools the playbook asks for (get_memory, update_memory, ...) prompting on every call: a
|
|
399
|
+
// prompt per call is reason enough for an agent to fall back to its native tools. Lemma's
|
|
400
|
+
// entries are dropped from the legacy key; anything else in it is the user's and stays.
|
|
401
|
+
const legacy = (settings.allowedTools || []).filter((tool) => !tool.startsWith('mcp__lemma__'));
|
|
402
|
+
if (legacy.length > 0) settings.allowedTools = legacy;
|
|
403
|
+
else delete settings.allowedTools;
|
|
404
|
+
settings.permissions = settings.permissions && typeof settings.permissions === 'object' ? settings.permissions : {};
|
|
405
|
+
const allow = Array.isArray(settings.permissions.allow) ? settings.permissions.allow : [];
|
|
406
|
+
settings.permissions.allow = Array.from(new Set([...allow, ...LEMMA_PREAPPROVED_TOOLS]));
|
|
371
407
|
|
|
372
408
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf8');
|
|
373
409
|
|
|
@@ -428,13 +464,13 @@ function configureClaudeCodeGateway(anthropicApiKey) {
|
|
|
428
464
|
return { activated: true, settingsPath: claudeSettingsPath };
|
|
429
465
|
}
|
|
430
466
|
|
|
431
|
-
const LEMMA_RULES_CONTENT = `# Lemma MCP —
|
|
432
|
-
|
|
433
|
-
> ⚠️ MANDATORY RULES — Follow without exception **for MCP-native clients**.
|
|
467
|
+
const LEMMA_RULES_CONTENT = `# Lemma MCP — When to use it
|
|
434
468
|
|
|
435
|
-
The MCP server \`lemma\` is connected.
|
|
436
|
-
|
|
437
|
-
|
|
469
|
+
The MCP server \`lemma\` is connected. What it does that your native tools can't is
|
|
470
|
+
**remember across sessions**: the Brain keeps verified fixes and decisions and flags them when
|
|
471
|
+
the code they depend on changes. That only pays off if it is consulted and fed, so the moments
|
|
472
|
+
below are not optional for MCP-native clients (Claude Code, Cursor, Codex, Windsurf, Kiro,
|
|
473
|
+
OpenCode).
|
|
438
474
|
|
|
439
475
|
> **Muse Code:** you DO NOT have native \`mcp__lemma__*\` tools. At session
|
|
440
476
|
> start, load the \`lemma\` skill (user scope if present, else
|
|
@@ -444,36 +480,34 @@ when a Lemma equivalent exists.
|
|
|
444
480
|
> hard block; use \`lemma call\` when it actually helps. If no \`lemma\` skill
|
|
445
481
|
> is installed, tell the user to run \`npx @nxuss/lemma init\`.
|
|
446
482
|
|
|
447
|
-
##
|
|
483
|
+
## Triggers — always do these
|
|
448
484
|
|
|
449
|
-
|
|
485
|
+
| When… | Call | Why native isn't enough |
|
|
486
|
+
|---|---|---|
|
|
487
|
+
| Session start | \`get_project_onboarding\`, then \`search_memory\` with the task topic | The Brain may already hold the answer |
|
|
488
|
+
| Investigating a bug, an error, or a "why does X" | \`search_memory\` with the error text or question | grep can't find what was learned in another session |
|
|
489
|
+
| A 🧠 Lemma note names memories | \`get_memory\` on the top one | The note carries the headline; the body has the files and the reason |
|
|
490
|
+
| A fix is verified (tests pass, build ok, user confirmed) | \`store_memory\` with \`filePaths\`: the root cause, the trap or what didn't work — not a summary of what changed | Unsaved, the next session investigates it from scratch; a change summary is already in git log and nobody searches for it |
|
|
491
|
+
| A memory turned out outdated or wrong | \`update_memory\` / \`forget_memory\` | A near-duplicate leaves two versions and search mixes them |
|
|
492
|
+
| Reading code you haven't located yet, or that may hold secrets | \`search_workspace\` / \`read_workspace_file\` | They mask API keys before they reach your context |
|
|
493
|
+
| Applying a generated patch | \`validate_patch_sandbox\` first | Validate before writing, not after |
|
|
450
494
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
| Search your own memory | \`search_memory\` |
|
|
459
|
-
| Persist solutions | \`store_memory\` |
|
|
460
|
-
| Project context | \`get_project_onboarding\` |
|
|
461
|
-
| Runtime/bug context | \`get_telepathic_hints\` |
|
|
462
|
-
| Apply a patch | \`validate_patch_sandbox\` first |
|
|
463
|
-
|
|
464
|
-
## Mandatory Flow — Session Start
|
|
465
|
-
|
|
466
|
-
1. Call \`get_project_onboarding\` — understand the project
|
|
467
|
-
2. Call \`search_memory\` with the task topic — recall past solutions
|
|
468
|
-
3. When done: call \`store_memory\` with the solution
|
|
495
|
+
Outside those moments, use judgment: for a small file you already located, a native read costs
|
|
496
|
+
less than the round-trip, and for processes, ports or git Lemma has nothing to add.
|
|
497
|
+
|
|
498
|
+
## Bug Reporting
|
|
499
|
+
|
|
500
|
+
1. Call \`search_memory\` with the error message
|
|
501
|
+
2. Call \`get_telepathic_hints\` (via \`lemma_toolbox\`) with the relevant file
|
|
469
502
|
|
|
470
503
|
> Muse: use \`lemma call <tool>\` (or \`node ./lemma-proxy.cjs call <tool>\` in this repo — see \`.agents/skills/lemma/SKILL.md\`).
|
|
471
504
|
|
|
472
|
-
##
|
|
505
|
+
## One hard rule
|
|
473
506
|
|
|
474
|
-
|
|
475
|
-
|
|
507
|
+
Any answer that depends on a cache hit, an auto-suggested fix, or a file compressed for your own
|
|
508
|
+
context must be delivered with the real information and without hiding where it came from.
|
|
476
509
|
|
|
510
|
+
---
|
|
477
511
|
*Auto-generated by \`lemma init\` — @nxuss/lemma*
|
|
478
512
|
`;
|
|
479
513
|
|
|
@@ -491,14 +525,14 @@ function updateAgentsMd() {
|
|
|
491
525
|
const existing = fs.readFileSync(agentsMdPath, 'utf8');
|
|
492
526
|
if (!existing.includes('@nxuss/lemma')) {
|
|
493
527
|
fs.appendFileSync(agentsMdPath, '\n---\n\n' + LEMMA_RULES_CONTENT, 'utf8');
|
|
494
|
-
} else
|
|
495
|
-
//
|
|
496
|
-
//
|
|
528
|
+
} else {
|
|
529
|
+
// Replace Lemma's block in place — an older one (pre-Muse guard, the "never use native
|
|
530
|
+
// tools" table) or this one from an earlier release — preserving the user's content.
|
|
497
531
|
const lemmaBlockRegex = /# Lemma MCP[\s\S]*?\*Auto-generated by `lemma init` — @nxuss\/lemma\*/;
|
|
498
532
|
if (lemmaBlockRegex.test(existing)) {
|
|
499
533
|
const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
|
|
500
|
-
fs.writeFileSync(agentsMdPath, updated, 'utf8');
|
|
501
|
-
} else {
|
|
534
|
+
if (updated !== existing) fs.writeFileSync(agentsMdPath, updated, 'utf8');
|
|
535
|
+
} else if (!existing.includes('## Triggers')) {
|
|
502
536
|
// Fallback: append new block
|
|
503
537
|
fs.appendFileSync(agentsMdPath, '\n---\n\n' + LEMMA_RULES_CONTENT, 'utf8');
|
|
504
538
|
}
|
|
@@ -527,6 +561,11 @@ function updateWindsurfRules() {
|
|
|
527
561
|
const existing = fs.readFileSync(wsRulesPath, 'utf8');
|
|
528
562
|
if (!existing.includes('@nxuss/lemma')) {
|
|
529
563
|
fs.appendFileSync(wsRulesPath, '\n---\n\n' + LEMMA_RULES_CONTENT, 'utf8');
|
|
564
|
+
} else {
|
|
565
|
+
// Same in-place refresh as AGENTS.md.
|
|
566
|
+
const lemmaBlockRegex = /# Lemma MCP[\s\S]*?\*Auto-generated by `lemma init` — @nxuss\/lemma\*/;
|
|
567
|
+
const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
|
|
568
|
+
if (updated !== existing) fs.writeFileSync(wsRulesPath, updated, 'utf8');
|
|
530
569
|
}
|
|
531
570
|
} else {
|
|
532
571
|
fs.writeFileSync(wsRulesPath, LEMMA_RULES_CONTENT, 'utf8');
|
|
@@ -754,12 +793,10 @@ function ensureKiroMigratesAgentsMd() {
|
|
|
754
793
|
try {
|
|
755
794
|
if (fs.existsSync(agentsMdPath)) {
|
|
756
795
|
const existing = fs.readFileSync(agentsMdPath, 'utf8');
|
|
757
|
-
if (existing.includes('@nxuss/lemma')
|
|
796
|
+
if (existing.includes('@nxuss/lemma')) {
|
|
758
797
|
const lemmaBlockRegex = /# Lemma MCP[\s\S]*?\*Auto-generated by `lemma init` — @nxuss\/lemma\*/;
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
fs.writeFileSync(agentsMdPath, updated, 'utf8');
|
|
762
|
-
}
|
|
798
|
+
const updated = existing.replace(lemmaBlockRegex, LEMMA_RULES_CONTENT.trim());
|
|
799
|
+
if (updated !== existing) fs.writeFileSync(agentsMdPath, updated, 'utf8');
|
|
763
800
|
}
|
|
764
801
|
}
|
|
765
802
|
} catch {}
|
|
@@ -909,7 +946,7 @@ function parseInitArgs(argv = process.argv) {
|
|
|
909
946
|
};
|
|
910
947
|
}
|
|
911
948
|
|
|
912
|
-
// The hooks that feed the Brain (git post-
|
|
949
|
+
// The hooks that feed the Brain (git post-merge/post-checkout, and the PostToolUse
|
|
913
950
|
// hook of each agent host) live in src/cli/{gitHooks,hostHooks}.ts. They were only wired into the
|
|
914
951
|
// commander `init` in src/cli/lemma-proxy.ts, which the `lemma` binary (lemma-proxy.cjs → this
|
|
915
952
|
// file) never reaches — so `lemma init` reported success and installed none of them.
|
|
@@ -929,6 +966,7 @@ function installBrainFeeds(cwd = process.cwd(), home = os.homedir(), mods = null
|
|
|
929
966
|
if (hooks.manual) lines.push(`Git hooks live in versioned ${hooks.manual.hooksDir}/ — not touching them. To feed the Brain, add:\n${hooks.manual.snippet}`);
|
|
930
967
|
else if (changed.length > 0) lines.push(`Git hooks feed the Brain (${changed.join(', ')})`);
|
|
931
968
|
else if (hooks.skippedReason) lines.push(`Git hooks skipped: ${hooks.skippedReason}`);
|
|
969
|
+
if (hooks.removed && hooks.removed.length > 0) lines.push(`Git hooks no longer store every commit in the Brain (removed from ${hooks.removed.join(', ')})`);
|
|
932
970
|
for (const { host: name, outcome } of host.installHostHooks(cwd, home)) {
|
|
933
971
|
if (outcome.status === 'manual') lines.push(`${outcome.file} couldn't be merged safely — not touching it. For ${name}, add:\n${outcome.snippet}`);
|
|
934
972
|
else if (outcome.status !== 'unchanged') lines.push(`${name} hook ${outcome.status} (${outcome.file})`);
|
|
@@ -1025,7 +1063,7 @@ async function main(argv = process.argv) {
|
|
|
1025
1063
|
--gateway Reroute this user's Claude Code model traffic through the proxy
|
|
1026
1064
|
(~/.claude/settings.json). Requires ANTHROPIC_API_KEY in env.
|
|
1027
1065
|
Without it, Claude Code keeps its own auth untouched.
|
|
1028
|
-
--no-hooks Skip the hooks that feed the Brain (git post-
|
|
1066
|
+
--no-hooks Skip the hooks that feed the Brain (git post-merge/
|
|
1029
1067
|
post-checkout; Claude Code, Codex, Cursor and OpenCode tool hooks).
|
|
1030
1068
|
|
|
1031
1069
|
`);
|
|
@@ -1171,4 +1209,4 @@ if (require.main === module) {
|
|
|
1171
1209
|
});
|
|
1172
1210
|
}
|
|
1173
1211
|
|
|
1174
|
-
module.exports = { main, configureMuse, configureMuseUserSkill, updateAgentsMd, MUSE_SKILL_CONTENT, LEMMA_RULES_CONTENT, installProxyDaemon, removeProxyDaemon, parseInitArgs, createEnvFile, installBrainFeeds };
|
|
1212
|
+
module.exports = { main, configureMuse, configureMuseUserSkill, updateAgentsMd, configureClaudeCode, MUSE_SKILL_CONTENT, LEMMA_RULES_CONTENT, CLAUDE_MD_CONTENT, installProxyDaemon, removeProxyDaemon, parseInitArgs, createEnvFile, installBrainFeeds };
|