@nxuss/lemma 1.25.0 → 1.26.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -3
- package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/cjs/cli/lemma-proxy.js +10 -2
- package/dist/cjs/cli/lemma-proxy.js.map +1 -1
- package/dist/cjs/mcp/index.js +15 -0
- package/dist/cjs/mcp/index.js.map +1 -1
- package/dist/cjs/mcp/tools/memory.d.ts.map +1 -1
- package/dist/cjs/mcp/tools/memory.js +57 -7
- package/dist/cjs/mcp/tools/memory.js.map +1 -1
- package/dist/cjs/subconscious/TheBrainV2.d.ts +20 -0
- package/dist/cjs/subconscious/TheBrainV2.d.ts.map +1 -1
- package/dist/cjs/subconscious/TheBrainV2.js +76 -10
- package/dist/cjs/subconscious/TheBrainV2.js.map +1 -1
- package/dist/cjs/utils/ClipboardWatcher.d.ts +5 -2
- package/dist/cjs/utils/ClipboardWatcher.d.ts.map +1 -1
- package/dist/cjs/utils/ClipboardWatcher.js +38 -4
- package/dist/cjs/utils/ClipboardWatcher.js.map +1 -1
- package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
- package/dist/esm/cli/lemma-proxy.js +10 -2
- package/dist/esm/cli/lemma-proxy.js.map +1 -1
- package/dist/esm/mcp/index.js +15 -0
- package/dist/esm/mcp/index.js.map +1 -1
- package/dist/esm/mcp/tools/memory.d.ts.map +1 -1
- package/dist/esm/mcp/tools/memory.js +57 -7
- package/dist/esm/mcp/tools/memory.js.map +1 -1
- package/dist/esm/subconscious/TheBrainV2.d.ts +20 -0
- package/dist/esm/subconscious/TheBrainV2.d.ts.map +1 -1
- package/dist/esm/subconscious/TheBrainV2.js +75 -10
- package/dist/esm/subconscious/TheBrainV2.js.map +1 -1
- package/dist/esm/utils/ClipboardWatcher.d.ts +5 -2
- package/dist/esm/utils/ClipboardWatcher.d.ts.map +1 -1
- package/dist/esm/utils/ClipboardWatcher.js +39 -5
- package/dist/esm/utils/ClipboardWatcher.js.map +1 -1
- package/package.json +1 -1
|
@@ -27,6 +27,7 @@ exports.tokenize = tokenize;
|
|
|
27
27
|
exports.termFrequencies = termFrequencies;
|
|
28
28
|
exports.bm25Score = bm25Score;
|
|
29
29
|
exports.jaccardSimilarity = jaccardSimilarity;
|
|
30
|
+
exports.extractRepoPathsFromText = extractRepoPathsFromText;
|
|
30
31
|
exports.resolveFreshnessNode = resolveFreshnessNode;
|
|
31
32
|
exports.buildClaimIndex = buildClaimIndex;
|
|
32
33
|
exports.findBlastRadius = findBlastRadius;
|
|
@@ -815,6 +816,51 @@ function jaccardSimilarity(setA, setB) {
|
|
|
815
816
|
return intersection / (setA.size + setB.size - intersection);
|
|
816
817
|
}
|
|
817
818
|
// ─── Freshness (file-hash invalidation) ───────────────────────────────────────
|
|
819
|
+
/**
|
|
820
|
+
* Real repository files named in a memory's body — the raw material for turning an
|
|
821
|
+
* untracked entry into a verifiable one. Only paths that actually exist under the project
|
|
822
|
+
* root count: an anchor must stay portable, so references that resolve outside the repo
|
|
823
|
+
* (or into node_modules / generated output) are ignored, and `file:line` suffixes are
|
|
824
|
+
* stripped (`src/foo.ts:123` anchors to `src/foo.ts`). False positives self-filter by
|
|
825
|
+
* existence — a stray "auth.ts" in prose that no such file backs just never resolves.
|
|
826
|
+
*/
|
|
827
|
+
function extractRepoPathsFromText(text, opts = {}) {
|
|
828
|
+
const root = opts.root ?? process.cwd();
|
|
829
|
+
const max = opts.max ?? 10;
|
|
830
|
+
const found = [];
|
|
831
|
+
const seen = new Set();
|
|
832
|
+
// A dot-extension filename, optionally prefixed by ./ or a relative path. The character
|
|
833
|
+
// class excludes ':' so `src/foo.ts:123` captures `src/foo.ts` only (the line reference
|
|
834
|
+
// would otherwise defeat the extension anchor). Anchored to start-of-text or one of the
|
|
835
|
+
// delimiters one actually finds around a path in prose: whitespace, quotes, backticks,
|
|
836
|
+
// colons, and opening brackets.
|
|
837
|
+
const tokenRe = /(?:^|[\s"'`=([,:—-])((?:\.\/)?[A-Za-z0-9_][A-Za-z0-9_./-]*\.(?:ts|tsx|js|jsx|mjs|cjs|json|jsonc|yaml|yml|md|toml|txt|env|css|scss|html|py|go|rs|rb|sh|sql|graphql|vue|svelte|java|kt|swift|c|cpp|h|cs|php))(?::\d+)?/g;
|
|
838
|
+
for (const m of text.matchAll(tokenRe)) {
|
|
839
|
+
const raw = m[1];
|
|
840
|
+
if (seen.has(raw))
|
|
841
|
+
continue;
|
|
842
|
+
seen.add(raw);
|
|
843
|
+
const abs = path_1.default.resolve(root, raw);
|
|
844
|
+
const rel = path_1.default.relative(root, abs);
|
|
845
|
+
if (rel.startsWith('..') || path_1.default.isAbsolute(rel))
|
|
846
|
+
continue; // outside the repo
|
|
847
|
+
if (/(?:^|\/)(?:node_modules|\.git|\.next|coverage|dist)(?:\/|$)/.test(rel))
|
|
848
|
+
continue;
|
|
849
|
+
let st;
|
|
850
|
+
try {
|
|
851
|
+
st = fs_1.default.statSync(abs);
|
|
852
|
+
}
|
|
853
|
+
catch {
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
if (!st.isFile())
|
|
857
|
+
continue;
|
|
858
|
+
found.push(rel);
|
|
859
|
+
if (found.length >= max)
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
return found;
|
|
863
|
+
}
|
|
818
864
|
function hashFilesForFreshness(filePaths) {
|
|
819
865
|
const hashes = {};
|
|
820
866
|
for (const p of filePaths) {
|
|
@@ -1846,6 +1892,7 @@ class TheBrainV2 {
|
|
|
1846
1892
|
const { fresh, staleFiles, unverifiedFiles, cosmeticChanges } = checkEntryFreshness(r.entry, resolver, resolveNode, 0, new Set(), semanticDiff);
|
|
1847
1893
|
const claims = r.entry.claims?.map((c) => checkClaimFreshness(c, resolver, semanticDiff));
|
|
1848
1894
|
const unverified = unverifiedFiles.length > 0;
|
|
1895
|
+
const untracked = trackedArtifactCount(r.entry) === 0;
|
|
1849
1896
|
return {
|
|
1850
1897
|
id: r.entry.id,
|
|
1851
1898
|
query: r.entry.query,
|
|
@@ -1854,6 +1901,7 @@ class TheBrainV2 {
|
|
|
1854
1901
|
provider: r.entry.provider,
|
|
1855
1902
|
timestamp: r.entry.timestamp,
|
|
1856
1903
|
fresh,
|
|
1904
|
+
...(untracked ? { untracked: true } : {}),
|
|
1857
1905
|
...(r.entry.hits ? { hits: r.entry.hits } : {}),
|
|
1858
1906
|
...(r.entry.tokensSaved ? { tokensSaved: r.entry.tokensSaved } : {}),
|
|
1859
1907
|
...(r.whyShown.length > 0 ? { whyShown: r.whyShown } : {}),
|
|
@@ -1870,11 +1918,15 @@ class TheBrainV2 {
|
|
|
1870
1918
|
if (countStats) {
|
|
1871
1919
|
if (results.length > 0) {
|
|
1872
1920
|
this.sessionHits++;
|
|
1873
|
-
//
|
|
1874
|
-
|
|
1875
|
-
if (
|
|
1876
|
-
|
|
1877
|
-
this.
|
|
1921
|
+
// An untracked result is a hint about something that was never validated against
|
|
1922
|
+
// code — counting it as a reuse would inflate the ROI/eviction ledger.
|
|
1923
|
+
if (!results[0].untracked) {
|
|
1924
|
+
// Increment hit counter on top result (LRU-style freshness)
|
|
1925
|
+
const topEntry = this.entries.get(results[0].id);
|
|
1926
|
+
if (topEntry) {
|
|
1927
|
+
topEntry.hits++;
|
|
1928
|
+
this.scheduleSave();
|
|
1929
|
+
}
|
|
1878
1930
|
}
|
|
1879
1931
|
}
|
|
1880
1932
|
else {
|
|
@@ -1933,10 +1985,13 @@ class TheBrainV2 {
|
|
|
1933
1985
|
if (options.countStats !== false) {
|
|
1934
1986
|
if (results.length > 0) {
|
|
1935
1987
|
this.sessionHits++;
|
|
1936
|
-
|
|
1937
|
-
if (
|
|
1938
|
-
topEntry.
|
|
1939
|
-
|
|
1988
|
+
// Same untracked gate as search(): never credit a hint with no evidence behind it.
|
|
1989
|
+
if (!results[0].untracked) {
|
|
1990
|
+
const topEntry = this.entries.get(results[0].id);
|
|
1991
|
+
if (topEntry) {
|
|
1992
|
+
topEntry.hits++;
|
|
1993
|
+
this.scheduleSave();
|
|
1994
|
+
}
|
|
1940
1995
|
}
|
|
1941
1996
|
}
|
|
1942
1997
|
else {
|
|
@@ -2806,7 +2861,18 @@ class TheBrainV2 {
|
|
|
2806
2861
|
revalidated.stale.push({ id: v.id, query: queryOf(v.id), staleFiles: v.staleFiles || [], action: 'refresh_memory after checking it is still true' });
|
|
2807
2862
|
}
|
|
2808
2863
|
else if (v.status === 'untracked') {
|
|
2809
|
-
|
|
2864
|
+
const entry = this.entries.get(v.id);
|
|
2865
|
+
const candidates = entry
|
|
2866
|
+
? extractRepoPathsFromText(`${entry.query}\n${entry.response}`, { max: 10 })
|
|
2867
|
+
: [];
|
|
2868
|
+
revalidated.untracked.push({
|
|
2869
|
+
id: v.id,
|
|
2870
|
+
query: queryOf(v.id),
|
|
2871
|
+
action: candidates.length > 0
|
|
2872
|
+
? 'refresh_memory with the discovered filePaths (auto-anchor)'
|
|
2873
|
+
: 'update_memory with filePaths/symbols so it becomes verifiable',
|
|
2874
|
+
anchorCandidates: candidates.length > 0 ? candidates : undefined,
|
|
2875
|
+
});
|
|
2810
2876
|
}
|
|
2811
2877
|
else if (v.status === 'unverified') {
|
|
2812
2878
|
revalidated.unverified.push({ id: v.id, query: queryOf(v.id), action: 'check the tracked paths exist on this machine, then refresh_memory' });
|