@mnemoai/core 1.1.0 → 1.1.2
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/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +7 -0
- package/dist/index.d.ts +136 -0
- package/dist/index.d.ts.map +1 -0
- package/{index.ts → dist/index.js} +537 -1333
- package/dist/index.js.map +7 -0
- package/dist/src/access-tracker.d.ts +97 -0
- package/dist/src/access-tracker.d.ts.map +1 -0
- package/dist/src/access-tracker.js +184 -0
- package/dist/src/access-tracker.js.map +7 -0
- package/dist/src/adapters/chroma.d.ts +31 -0
- package/dist/src/adapters/chroma.d.ts.map +1 -0
- package/{src/adapters/chroma.ts → dist/src/adapters/chroma.js} +45 -107
- package/dist/src/adapters/chroma.js.map +7 -0
- package/dist/src/adapters/lancedb.d.ts +29 -0
- package/dist/src/adapters/lancedb.d.ts.map +1 -0
- package/{src/adapters/lancedb.ts → dist/src/adapters/lancedb.js} +41 -109
- package/dist/src/adapters/lancedb.js.map +7 -0
- package/dist/src/adapters/pgvector.d.ts +33 -0
- package/dist/src/adapters/pgvector.d.ts.map +1 -0
- package/{src/adapters/pgvector.ts → dist/src/adapters/pgvector.js} +42 -104
- package/dist/src/adapters/pgvector.js.map +7 -0
- package/dist/src/adapters/qdrant.d.ts +34 -0
- package/dist/src/adapters/qdrant.d.ts.map +1 -0
- package/dist/src/adapters/qdrant.js +132 -0
- package/dist/src/adapters/qdrant.js.map +7 -0
- package/dist/src/adaptive-retrieval.d.ts +14 -0
- package/dist/src/adaptive-retrieval.d.ts.map +1 -0
- package/dist/src/adaptive-retrieval.js +52 -0
- package/dist/src/adaptive-retrieval.js.map +7 -0
- package/dist/src/audit-log.d.ts +56 -0
- package/dist/src/audit-log.d.ts.map +1 -0
- package/dist/src/audit-log.js +139 -0
- package/dist/src/audit-log.js.map +7 -0
- package/dist/src/chunker.d.ts +45 -0
- package/dist/src/chunker.d.ts.map +1 -0
- package/dist/src/chunker.js +157 -0
- package/dist/src/chunker.js.map +7 -0
- package/dist/src/config.d.ts +70 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +142 -0
- package/dist/src/config.js.map +7 -0
- package/dist/src/decay-engine.d.ts +73 -0
- package/dist/src/decay-engine.d.ts.map +1 -0
- package/dist/src/decay-engine.js +119 -0
- package/dist/src/decay-engine.js.map +7 -0
- package/dist/src/embedder.d.ts +94 -0
- package/dist/src/embedder.d.ts.map +1 -0
- package/{src/embedder.ts → dist/src/embedder.js} +119 -317
- package/dist/src/embedder.js.map +7 -0
- package/dist/src/extraction-prompts.d.ts +12 -0
- package/dist/src/extraction-prompts.d.ts.map +1 -0
- package/dist/src/extraction-prompts.js +311 -0
- package/dist/src/extraction-prompts.js.map +7 -0
- package/dist/src/license.d.ts +29 -0
- package/dist/src/license.d.ts.map +1 -0
- package/{src/license.ts → dist/src/license.js} +42 -113
- package/dist/src/license.js.map +7 -0
- package/dist/src/llm-client.d.ts +23 -0
- package/dist/src/llm-client.d.ts.map +1 -0
- package/{src/llm-client.ts → dist/src/llm-client.js} +22 -55
- package/dist/src/llm-client.js.map +7 -0
- package/dist/src/logger.d.ts +33 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +35 -0
- package/dist/src/logger.js.map +7 -0
- package/dist/src/mcp-server.d.ts +16 -0
- package/dist/src/mcp-server.d.ts.map +1 -0
- package/{src/mcp-server.ts → dist/src/mcp-server.js} +81 -181
- package/dist/src/mcp-server.js.map +7 -0
- package/dist/src/memory-categories.d.ts +40 -0
- package/dist/src/memory-categories.d.ts.map +1 -0
- package/dist/src/memory-categories.js +33 -0
- package/dist/src/memory-categories.js.map +7 -0
- package/dist/src/memory-upgrader.d.ts +71 -0
- package/dist/src/memory-upgrader.d.ts.map +1 -0
- package/dist/src/memory-upgrader.js +238 -0
- package/dist/src/memory-upgrader.js.map +7 -0
- package/dist/src/migrate.d.ts +47 -0
- package/dist/src/migrate.d.ts.map +1 -0
- package/{src/migrate.ts → dist/src/migrate.js} +57 -165
- package/dist/src/migrate.js.map +7 -0
- package/dist/src/mnemo.d.ts +67 -0
- package/dist/src/mnemo.d.ts.map +1 -0
- package/dist/src/mnemo.js +66 -0
- package/dist/src/mnemo.js.map +7 -0
- package/dist/src/noise-filter.d.ts +23 -0
- package/dist/src/noise-filter.d.ts.map +1 -0
- package/dist/src/noise-filter.js +62 -0
- package/dist/src/noise-filter.js.map +7 -0
- package/dist/src/noise-prototypes.d.ts +40 -0
- package/dist/src/noise-prototypes.d.ts.map +1 -0
- package/dist/src/noise-prototypes.js +116 -0
- package/dist/src/noise-prototypes.js.map +7 -0
- package/dist/src/observability.d.ts +16 -0
- package/dist/src/observability.d.ts.map +1 -0
- package/dist/src/observability.js +53 -0
- package/dist/src/observability.js.map +7 -0
- package/dist/src/query-tracker.d.ts +27 -0
- package/dist/src/query-tracker.d.ts.map +1 -0
- package/dist/src/query-tracker.js +32 -0
- package/dist/src/query-tracker.js.map +7 -0
- package/dist/src/reflection-event-store.d.ts +44 -0
- package/dist/src/reflection-event-store.d.ts.map +1 -0
- package/dist/src/reflection-event-store.js +50 -0
- package/dist/src/reflection-event-store.js.map +7 -0
- package/dist/src/reflection-item-store.d.ts +58 -0
- package/dist/src/reflection-item-store.d.ts.map +1 -0
- package/dist/src/reflection-item-store.js +69 -0
- package/dist/src/reflection-item-store.js.map +7 -0
- package/dist/src/reflection-mapped-metadata.d.ts +47 -0
- package/dist/src/reflection-mapped-metadata.d.ts.map +1 -0
- package/dist/src/reflection-mapped-metadata.js +40 -0
- package/dist/src/reflection-mapped-metadata.js.map +7 -0
- package/dist/src/reflection-metadata.d.ts +11 -0
- package/dist/src/reflection-metadata.d.ts.map +1 -0
- package/dist/src/reflection-metadata.js +24 -0
- package/dist/src/reflection-metadata.js.map +7 -0
- package/dist/src/reflection-ranking.d.ts +13 -0
- package/dist/src/reflection-ranking.d.ts.map +1 -0
- package/{src/reflection-ranking.ts → dist/src/reflection-ranking.js} +12 -21
- package/dist/src/reflection-ranking.js.map +7 -0
- package/dist/src/reflection-retry.d.ts +30 -0
- package/dist/src/reflection-retry.d.ts.map +1 -0
- package/{src/reflection-retry.ts → dist/src/reflection-retry.js} +24 -64
- package/dist/src/reflection-retry.js.map +7 -0
- package/dist/src/reflection-slices.d.ts +42 -0
- package/dist/src/reflection-slices.d.ts.map +1 -0
- package/{src/reflection-slices.ts → dist/src/reflection-slices.js} +60 -136
- package/dist/src/reflection-slices.js.map +7 -0
- package/dist/src/reflection-store.d.ts +85 -0
- package/dist/src/reflection-store.d.ts.map +1 -0
- package/dist/src/reflection-store.js +407 -0
- package/dist/src/reflection-store.js.map +7 -0
- package/dist/src/resonance-state.d.ts +19 -0
- package/dist/src/resonance-state.d.ts.map +1 -0
- package/{src/resonance-state.ts → dist/src/resonance-state.js} +13 -42
- package/dist/src/resonance-state.js.map +7 -0
- package/dist/src/retriever.d.ts +228 -0
- package/dist/src/retriever.d.ts.map +1 -0
- package/dist/src/retriever.js +1006 -0
- package/dist/src/retriever.js.map +7 -0
- package/dist/src/scopes.d.ts +58 -0
- package/dist/src/scopes.d.ts.map +1 -0
- package/dist/src/scopes.js +252 -0
- package/dist/src/scopes.js.map +7 -0
- package/dist/src/self-improvement-files.d.ts +20 -0
- package/dist/src/self-improvement-files.d.ts.map +1 -0
- package/{src/self-improvement-files.ts → dist/src/self-improvement-files.js} +24 -49
- package/dist/src/self-improvement-files.js.map +7 -0
- package/dist/src/semantic-gate.d.ts +24 -0
- package/dist/src/semantic-gate.d.ts.map +1 -0
- package/dist/src/semantic-gate.js +86 -0
- package/dist/src/semantic-gate.js.map +7 -0
- package/dist/src/session-recovery.d.ts +9 -0
- package/dist/src/session-recovery.d.ts.map +1 -0
- package/{src/session-recovery.ts → dist/src/session-recovery.js} +40 -57
- package/dist/src/session-recovery.js.map +7 -0
- package/dist/src/smart-extractor.d.ts +107 -0
- package/dist/src/smart-extractor.d.ts.map +1 -0
- package/{src/smart-extractor.ts → dist/src/smart-extractor.js} +130 -383
- package/dist/src/smart-extractor.js.map +7 -0
- package/dist/src/smart-metadata.d.ts +103 -0
- package/dist/src/smart-metadata.d.ts.map +1 -0
- package/dist/src/smart-metadata.js +361 -0
- package/dist/src/smart-metadata.js.map +7 -0
- package/dist/src/storage-adapter.d.ts +102 -0
- package/dist/src/storage-adapter.d.ts.map +1 -0
- package/dist/src/storage-adapter.js +22 -0
- package/dist/src/storage-adapter.js.map +7 -0
- package/dist/src/store.d.ts +108 -0
- package/dist/src/store.d.ts.map +1 -0
- package/dist/src/store.js +939 -0
- package/dist/src/store.js.map +7 -0
- package/dist/src/tier-manager.d.ts +57 -0
- package/dist/src/tier-manager.d.ts.map +1 -0
- package/dist/src/tier-manager.js +80 -0
- package/dist/src/tier-manager.js.map +7 -0
- package/dist/src/tools.d.ts +43 -0
- package/dist/src/tools.d.ts.map +1 -0
- package/dist/src/tools.js +1075 -0
- package/dist/src/tools.js.map +7 -0
- package/dist/src/wal-recovery.d.ts +30 -0
- package/dist/src/wal-recovery.d.ts.map +1 -0
- package/{src/wal-recovery.ts → dist/src/wal-recovery.js} +26 -79
- package/dist/src/wal-recovery.js.map +7 -0
- package/package.json +21 -2
- package/openclaw.plugin.json +0 -815
- package/src/access-tracker.ts +0 -341
- package/src/adapters/README.md +0 -78
- package/src/adapters/qdrant.ts +0 -191
- package/src/adaptive-retrieval.ts +0 -90
- package/src/audit-log.ts +0 -238
- package/src/chunker.ts +0 -254
- package/src/config.ts +0 -271
- package/src/decay-engine.ts +0 -238
- package/src/extraction-prompts.ts +0 -339
- package/src/memory-categories.ts +0 -71
- package/src/memory-upgrader.ts +0 -388
- package/src/mnemo.ts +0 -142
- package/src/noise-filter.ts +0 -97
- package/src/noise-prototypes.ts +0 -164
- package/src/observability.ts +0 -81
- package/src/query-tracker.ts +0 -57
- package/src/reflection-event-store.ts +0 -98
- package/src/reflection-item-store.ts +0 -112
- package/src/reflection-mapped-metadata.ts +0 -84
- package/src/reflection-metadata.ts +0 -23
- package/src/reflection-store.ts +0 -602
- package/src/retriever.ts +0 -1510
- package/src/scopes.ts +0 -375
- package/src/semantic-gate.ts +0 -121
- package/src/smart-metadata.ts +0 -561
- package/src/storage-adapter.ts +0 -153
- package/src/store.ts +0 -1330
- package/src/tier-manager.ts +0 -189
- package/src/tools.ts +0 -1292
- package/test/core.test.mjs +0 -301
|
@@ -1,132 +1,79 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
/**
|
|
3
|
-
* Mnemo Pro License Validation
|
|
4
|
-
*
|
|
5
|
-
* Two modes:
|
|
6
|
-
* 1. MNEMO_PRO_KEY — pre-activated key (offline, machine-bound)
|
|
7
|
-
* 2. MNEMO_LICENSE_TOKEN — auto-activate on first run (online, one-time)
|
|
8
|
-
*
|
|
9
|
-
* Machine fingerprint: SHA-256(hostname + arch + cpuModel + platform)
|
|
10
|
-
* Indie keys are bound to one machine. Team/Enterprise keys are per-seat.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
1
|
import { verify, createPublicKey, createHash } from "node:crypto";
|
|
14
2
|
import { hostname, arch, cpus, platform } from "node:os";
|
|
15
3
|
import { homedir } from "node:os";
|
|
16
4
|
import { join } from "node:path";
|
|
17
5
|
import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
"MCowBQYDK2VwAyEAe8cshR0FAlDoILPw0aW1AyUNGbQXSOZaQKEZ7T2mXV8=";
|
|
22
|
-
|
|
23
|
-
const ACTIVATION_URL =
|
|
24
|
-
process.env.MNEMO_ACTIVATION_URL || "https://activation.m-nemo.ai";
|
|
25
|
-
|
|
6
|
+
import { log } from "./logger.js";
|
|
7
|
+
const PUBLIC_KEY_B64 = "MCowBQYDK2VwAyEAe8cshR0FAlDoILPw0aW1AyUNGbQXSOZaQKEZ7T2mXV8=";
|
|
8
|
+
const ACTIVATION_URL = process.env.MNEMO_ACTIVATION_URL || "https://activation.m-nemo.ai";
|
|
26
9
|
const KEY_CACHE_PATH = join(homedir(), ".mnemo", "pro-key.json");
|
|
27
|
-
|
|
28
|
-
let
|
|
29
|
-
let _cachedPayload: LicensePayload | null = null;
|
|
10
|
+
let _cachedResult = null;
|
|
11
|
+
let _cachedPayload = null;
|
|
30
12
|
let _warnedOnce = false;
|
|
31
|
-
|
|
32
|
-
export interface LicensePayload {
|
|
33
|
-
licensee: string;
|
|
34
|
-
email: string;
|
|
35
|
-
plan: "indie" | "team" | "enterprise";
|
|
36
|
-
issued: string;
|
|
37
|
-
expires: string;
|
|
38
|
-
machine_id?: string;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// ── Machine Fingerprint ──
|
|
42
|
-
|
|
43
|
-
export function getMachineFingerprint(): string {
|
|
13
|
+
function getMachineFingerprint() {
|
|
44
14
|
const cpu = cpus()[0]?.model || "unknown";
|
|
45
15
|
const raw = `${hostname()}:${arch()}:${cpu}:${platform()}`;
|
|
46
16
|
return createHash("sha256").update(raw).digest("hex");
|
|
47
17
|
}
|
|
48
|
-
|
|
49
|
-
// ── Key Verification (offline) ──
|
|
50
|
-
|
|
51
|
-
function verifyKey(key: string): LicensePayload | null {
|
|
18
|
+
function verifyKey(key) {
|
|
52
19
|
const dotIdx = key.indexOf(".");
|
|
53
20
|
if (dotIdx < 1) return null;
|
|
54
|
-
|
|
55
21
|
try {
|
|
56
22
|
const payloadBuf = Buffer.from(key.slice(0, dotIdx), "base64");
|
|
57
23
|
const signatureBuf = Buffer.from(key.slice(dotIdx + 1), "base64");
|
|
58
|
-
|
|
59
24
|
const pubKeyObj = createPublicKey({
|
|
60
25
|
key: Buffer.from(PUBLIC_KEY_B64, "base64"),
|
|
61
26
|
format: "der",
|
|
62
|
-
type: "spki"
|
|
27
|
+
type: "spki"
|
|
63
28
|
});
|
|
64
|
-
|
|
65
29
|
const valid = verify(null, payloadBuf, pubKeyObj, signatureBuf);
|
|
66
30
|
if (!valid) return null;
|
|
67
|
-
|
|
68
|
-
const payload: LicensePayload = JSON.parse(payloadBuf.toString("utf8"));
|
|
69
|
-
|
|
70
|
-
// Check expiry
|
|
31
|
+
const payload = JSON.parse(payloadBuf.toString("utf8"));
|
|
71
32
|
if (payload.expires) {
|
|
72
33
|
if (new Date(payload.expires).getTime() < Date.now()) return null;
|
|
73
34
|
}
|
|
74
|
-
|
|
75
|
-
// Check machine binding (if present in payload)
|
|
76
35
|
if (payload.machine_id) {
|
|
77
36
|
const localFP = getMachineFingerprint();
|
|
78
37
|
if (payload.machine_id !== localFP) return null;
|
|
79
38
|
}
|
|
80
|
-
|
|
81
39
|
return payload;
|
|
82
40
|
} catch {
|
|
83
41
|
return null;
|
|
84
42
|
}
|
|
85
43
|
}
|
|
86
|
-
|
|
87
|
-
// ── Auto-Activation (online, one-time) ──
|
|
88
|
-
|
|
89
|
-
async function autoActivate(token: string): Promise<string | null> {
|
|
44
|
+
async function autoActivate(token) {
|
|
90
45
|
try {
|
|
91
46
|
const machine_id = getMachineFingerprint();
|
|
92
47
|
const resp = await fetch(`${ACTIVATION_URL}/activate`, {
|
|
93
48
|
method: "POST",
|
|
94
49
|
headers: { "Content-Type": "application/json" },
|
|
95
50
|
body: JSON.stringify({ token, machine_id }),
|
|
96
|
-
signal: AbortSignal.timeout(
|
|
51
|
+
signal: AbortSignal.timeout(1e4)
|
|
97
52
|
});
|
|
98
|
-
|
|
99
53
|
if (!resp.ok) {
|
|
100
|
-
const err = await resp.json().catch(() => ({}))
|
|
54
|
+
const err = await resp.json().catch(() => ({}));
|
|
101
55
|
if (resp.status === 409) {
|
|
102
|
-
|
|
103
|
-
`
|
|
104
|
-
`Visit https://m-nemo.ai/pro/migrate to transfer.`
|
|
56
|
+
log.warn(
|
|
57
|
+
`License token already activated on another device. Visit https://m-nemo.ai/pro/migrate to transfer.`
|
|
105
58
|
);
|
|
106
59
|
} else {
|
|
107
|
-
|
|
60
|
+
log.warn(`Activation failed: ${err.error || resp.status}`);
|
|
108
61
|
}
|
|
109
62
|
return null;
|
|
110
63
|
}
|
|
111
|
-
|
|
112
|
-
const { key } = await resp.json() as { key: string };
|
|
113
|
-
|
|
114
|
-
// Cache the activated key locally
|
|
64
|
+
const { key } = await resp.json();
|
|
115
65
|
try {
|
|
116
66
|
mkdirSync(join(homedir(), ".mnemo"), { recursive: true });
|
|
117
|
-
writeFileSync(KEY_CACHE_PATH, JSON.stringify({ key, token, activated: new Date().toISOString() }));
|
|
118
|
-
} catch {
|
|
119
|
-
|
|
67
|
+
writeFileSync(KEY_CACHE_PATH, JSON.stringify({ key, token, activated: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
120
70
|
return key;
|
|
121
71
|
} catch (err) {
|
|
122
|
-
|
|
72
|
+
log.warn(`Activation request failed (offline?): ${err}`);
|
|
123
73
|
return null;
|
|
124
74
|
}
|
|
125
75
|
}
|
|
126
|
-
|
|
127
|
-
// ── Load cached key from disk ──
|
|
128
|
-
|
|
129
|
-
function loadCachedKey(): string | null {
|
|
76
|
+
function loadCachedKey() {
|
|
130
77
|
try {
|
|
131
78
|
const data = JSON.parse(readFileSync(KEY_CACHE_PATH, "utf8"));
|
|
132
79
|
return data.key || null;
|
|
@@ -134,13 +81,8 @@ function loadCachedKey(): string | null {
|
|
|
134
81
|
return null;
|
|
135
82
|
}
|
|
136
83
|
}
|
|
137
|
-
|
|
138
|
-
// ── Main entry point ──
|
|
139
|
-
|
|
140
|
-
export function isProLicensed(): boolean {
|
|
84
|
+
function isProLicensed() {
|
|
141
85
|
if (_cachedResult !== null) return _cachedResult;
|
|
142
|
-
|
|
143
|
-
// Priority 1: explicit MNEMO_PRO_KEY env var
|
|
144
86
|
const explicitKey = process.env.MNEMO_PRO_KEY?.trim();
|
|
145
87
|
if (explicitKey) {
|
|
146
88
|
const payload = verifyKey(explicitKey);
|
|
@@ -150,8 +92,6 @@ export function isProLicensed(): boolean {
|
|
|
150
92
|
return true;
|
|
151
93
|
}
|
|
152
94
|
}
|
|
153
|
-
|
|
154
|
-
// Priority 2: cached key from previous activation
|
|
155
95
|
const cachedKey = loadCachedKey();
|
|
156
96
|
if (cachedKey) {
|
|
157
97
|
const payload = verifyKey(cachedKey);
|
|
@@ -161,35 +101,25 @@ export function isProLicensed(): boolean {
|
|
|
161
101
|
return true;
|
|
162
102
|
}
|
|
163
103
|
}
|
|
164
|
-
|
|
165
|
-
// Priority 3: auto-activate with token (async — won't block first call)
|
|
166
104
|
const token = process.env.MNEMO_LICENSE_TOKEN?.trim();
|
|
167
105
|
if (token) {
|
|
168
|
-
// Fire and forget — next process start will pick up cached key
|
|
169
106
|
autoActivate(token).then((key) => {
|
|
170
107
|
if (key) {
|
|
171
108
|
const payload = verifyKey(key);
|
|
172
109
|
if (payload) {
|
|
173
110
|
_cachedPayload = payload;
|
|
174
111
|
_cachedResult = true;
|
|
175
|
-
|
|
112
|
+
log.info(`Pro license activated for ${payload.licensee} (${payload.plan})`);
|
|
176
113
|
}
|
|
177
114
|
}
|
|
178
|
-
}).catch(() => {
|
|
115
|
+
}).catch(() => {
|
|
116
|
+
});
|
|
179
117
|
}
|
|
180
|
-
|
|
181
118
|
_cachedResult = false;
|
|
182
119
|
return false;
|
|
183
120
|
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Async version — waits for activation to complete if token is present.
|
|
187
|
-
* Use this during plugin initialization.
|
|
188
|
-
*/
|
|
189
|
-
export async function ensureProLicense(): Promise<boolean> {
|
|
121
|
+
async function ensureProLicense() {
|
|
190
122
|
if (_cachedResult !== null) return _cachedResult;
|
|
191
|
-
|
|
192
|
-
// Check explicit key
|
|
193
123
|
const explicitKey = process.env.MNEMO_PRO_KEY?.trim();
|
|
194
124
|
if (explicitKey) {
|
|
195
125
|
const payload = verifyKey(explicitKey);
|
|
@@ -199,8 +129,6 @@ export async function ensureProLicense(): Promise<boolean> {
|
|
|
199
129
|
return true;
|
|
200
130
|
}
|
|
201
131
|
}
|
|
202
|
-
|
|
203
|
-
// Check cached key
|
|
204
132
|
const cachedKey = loadCachedKey();
|
|
205
133
|
if (cachedKey) {
|
|
206
134
|
const payload = verifyKey(cachedKey);
|
|
@@ -210,8 +138,6 @@ export async function ensureProLicense(): Promise<boolean> {
|
|
|
210
138
|
return true;
|
|
211
139
|
}
|
|
212
140
|
}
|
|
213
|
-
|
|
214
|
-
// Try auto-activate with token
|
|
215
141
|
const token = process.env.MNEMO_LICENSE_TOKEN?.trim();
|
|
216
142
|
if (token) {
|
|
217
143
|
const key = await autoActivate(token);
|
|
@@ -220,39 +146,42 @@ export async function ensureProLicense(): Promise<boolean> {
|
|
|
220
146
|
if (payload) {
|
|
221
147
|
_cachedPayload = payload;
|
|
222
148
|
_cachedResult = true;
|
|
223
|
-
|
|
149
|
+
log.info(`Pro license activated for ${payload.licensee} (${payload.plan})`);
|
|
224
150
|
return true;
|
|
225
151
|
}
|
|
226
152
|
}
|
|
227
153
|
}
|
|
228
|
-
|
|
229
154
|
_cachedResult = false;
|
|
230
155
|
return false;
|
|
231
156
|
}
|
|
232
|
-
|
|
233
|
-
export function getLicenseInfo(): LicensePayload | null {
|
|
157
|
+
function getLicenseInfo() {
|
|
234
158
|
isProLicensed();
|
|
235
159
|
return _cachedPayload;
|
|
236
160
|
}
|
|
237
|
-
|
|
238
|
-
export function requirePro(featureName: string): boolean {
|
|
161
|
+
function requirePro(featureName) {
|
|
239
162
|
if (isProLicensed()) return true;
|
|
240
|
-
|
|
241
163
|
if (!_warnedOnce) {
|
|
242
|
-
|
|
243
|
-
`
|
|
244
|
-
`Core functionality is fully available. https://m-nemo.ai/pro`,
|
|
164
|
+
log.warn(
|
|
165
|
+
`Pro features disabled \u2014 set MNEMO_PRO_KEY or MNEMO_LICENSE_TOKEN to enable. Core functionality is fully available. https://m-nemo.ai/pro`
|
|
245
166
|
);
|
|
246
167
|
_warnedOnce = true;
|
|
247
168
|
}
|
|
248
169
|
if (process.env.MNEMO_DEBUG) {
|
|
249
|
-
|
|
170
|
+
log.debug(`Pro feature skipped: ${featureName}`);
|
|
250
171
|
}
|
|
251
172
|
return false;
|
|
252
173
|
}
|
|
253
|
-
|
|
254
|
-
export function _resetLicenseCache(): void {
|
|
174
|
+
function _resetLicenseCache() {
|
|
255
175
|
_cachedResult = null;
|
|
256
176
|
_cachedPayload = null;
|
|
257
177
|
_warnedOnce = false;
|
|
258
178
|
}
|
|
179
|
+
export {
|
|
180
|
+
_resetLicenseCache,
|
|
181
|
+
ensureProLicense,
|
|
182
|
+
getLicenseInfo,
|
|
183
|
+
getMachineFingerprint,
|
|
184
|
+
isProLicensed,
|
|
185
|
+
requirePro
|
|
186
|
+
};
|
|
187
|
+
//# sourceMappingURL=license.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/license.ts"],
|
|
4
|
+
"sourcesContent": ["// SPDX-License-Identifier: MIT\n/**\n * Mnemo Pro License Validation\n *\n * Two modes:\n * 1. MNEMO_PRO_KEY \u2014 pre-activated key (offline, machine-bound)\n * 2. MNEMO_LICENSE_TOKEN \u2014 auto-activate on first run (online, one-time)\n *\n * Machine fingerprint: SHA-256(hostname + arch + cpuModel + platform)\n * Indie keys are bound to one machine. Team/Enterprise keys are per-seat.\n */\n\nimport { verify, createPublicKey, createHash } from \"node:crypto\";\nimport { hostname, arch, cpus, platform } from \"node:os\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { readFileSync, writeFileSync, mkdirSync } from \"node:fs\";\nimport { log } from \"./logger.js\";\n\n// Ed25519 public key (DER/SPKI, base64) \u2014 safe to publish\nconst PUBLIC_KEY_B64 =\n \"MCowBQYDK2VwAyEAe8cshR0FAlDoILPw0aW1AyUNGbQXSOZaQKEZ7T2mXV8=\";\n\nconst ACTIVATION_URL =\n process.env.MNEMO_ACTIVATION_URL || \"https://activation.m-nemo.ai\";\n\nconst KEY_CACHE_PATH = join(homedir(), \".mnemo\", \"pro-key.json\");\n\nlet _cachedResult: boolean | null = null;\nlet _cachedPayload: LicensePayload | null = null;\nlet _warnedOnce = false;\n\nexport interface LicensePayload {\n licensee: string;\n email: string;\n plan: \"indie\" | \"team\" | \"enterprise\";\n issued: string;\n expires: string;\n machine_id?: string;\n}\n\n// \u2500\u2500 Machine Fingerprint \u2500\u2500\n\nexport function getMachineFingerprint(): string {\n const cpu = cpus()[0]?.model || \"unknown\";\n const raw = `${hostname()}:${arch()}:${cpu}:${platform()}`;\n return createHash(\"sha256\").update(raw).digest(\"hex\");\n}\n\n// \u2500\u2500 Key Verification (offline) \u2500\u2500\n\nfunction verifyKey(key: string): LicensePayload | null {\n const dotIdx = key.indexOf(\".\");\n if (dotIdx < 1) return null;\n\n try {\n const payloadBuf = Buffer.from(key.slice(0, dotIdx), \"base64\");\n const signatureBuf = Buffer.from(key.slice(dotIdx + 1), \"base64\");\n\n const pubKeyObj = createPublicKey({\n key: Buffer.from(PUBLIC_KEY_B64, \"base64\"),\n format: \"der\",\n type: \"spki\",\n });\n\n const valid = verify(null, payloadBuf, pubKeyObj, signatureBuf);\n if (!valid) return null;\n\n const payload: LicensePayload = JSON.parse(payloadBuf.toString(\"utf8\"));\n\n // Check expiry\n if (payload.expires) {\n if (new Date(payload.expires).getTime() < Date.now()) return null;\n }\n\n // Check machine binding (if present in payload)\n if (payload.machine_id) {\n const localFP = getMachineFingerprint();\n if (payload.machine_id !== localFP) return null;\n }\n\n return payload;\n } catch {\n return null;\n }\n}\n\n// \u2500\u2500 Auto-Activation (online, one-time) \u2500\u2500\n\nasync function autoActivate(token: string): Promise<string | null> {\n try {\n const machine_id = getMachineFingerprint();\n const resp = await fetch(`${ACTIVATION_URL}/activate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ token, machine_id }),\n signal: AbortSignal.timeout(10000),\n });\n\n if (!resp.ok) {\n const err = await resp.json().catch(() => ({})) as any;\n if (resp.status === 409) {\n log.warn(\n `License token already activated on another device. ` +\n `Visit https://m-nemo.ai/pro/migrate to transfer.`\n );\n } else {\n log.warn(`Activation failed: ${err.error || resp.status}`);\n }\n return null;\n }\n\n const { key } = await resp.json() as { key: string };\n\n // Cache the activated key locally\n try {\n mkdirSync(join(homedir(), \".mnemo\"), { recursive: true });\n writeFileSync(KEY_CACHE_PATH, JSON.stringify({ key, token, activated: new Date().toISOString() }));\n } catch { /* non-fatal */ }\n\n return key;\n } catch (err) {\n log.warn(`Activation request failed (offline?): ${err}`);\n return null;\n }\n}\n\n// \u2500\u2500 Load cached key from disk \u2500\u2500\n\nfunction loadCachedKey(): string | null {\n try {\n const data = JSON.parse(readFileSync(KEY_CACHE_PATH, \"utf8\"));\n return data.key || null;\n } catch {\n return null;\n }\n}\n\n// \u2500\u2500 Main entry point \u2500\u2500\n\nexport function isProLicensed(): boolean {\n if (_cachedResult !== null) return _cachedResult;\n\n // Priority 1: explicit MNEMO_PRO_KEY env var\n const explicitKey = process.env.MNEMO_PRO_KEY?.trim();\n if (explicitKey) {\n const payload = verifyKey(explicitKey);\n if (payload) {\n _cachedPayload = payload;\n _cachedResult = true;\n return true;\n }\n }\n\n // Priority 2: cached key from previous activation\n const cachedKey = loadCachedKey();\n if (cachedKey) {\n const payload = verifyKey(cachedKey);\n if (payload) {\n _cachedPayload = payload;\n _cachedResult = true;\n return true;\n }\n }\n\n // Priority 3: auto-activate with token (async \u2014 won't block first call)\n const token = process.env.MNEMO_LICENSE_TOKEN?.trim();\n if (token) {\n // Fire and forget \u2014 next process start will pick up cached key\n autoActivate(token).then((key) => {\n if (key) {\n const payload = verifyKey(key);\n if (payload) {\n _cachedPayload = payload;\n _cachedResult = true;\n log.info(`Pro license activated for ${payload.licensee} (${payload.plan})`);\n }\n }\n }).catch(() => {});\n }\n\n _cachedResult = false;\n return false;\n}\n\n/**\n * Async version \u2014 waits for activation to complete if token is present.\n * Use this during plugin initialization.\n */\nexport async function ensureProLicense(): Promise<boolean> {\n if (_cachedResult !== null) return _cachedResult;\n\n // Check explicit key\n const explicitKey = process.env.MNEMO_PRO_KEY?.trim();\n if (explicitKey) {\n const payload = verifyKey(explicitKey);\n if (payload) {\n _cachedPayload = payload;\n _cachedResult = true;\n return true;\n }\n }\n\n // Check cached key\n const cachedKey = loadCachedKey();\n if (cachedKey) {\n const payload = verifyKey(cachedKey);\n if (payload) {\n _cachedPayload = payload;\n _cachedResult = true;\n return true;\n }\n }\n\n // Try auto-activate with token\n const token = process.env.MNEMO_LICENSE_TOKEN?.trim();\n if (token) {\n const key = await autoActivate(token);\n if (key) {\n const payload = verifyKey(key);\n if (payload) {\n _cachedPayload = payload;\n _cachedResult = true;\n log.info(`Pro license activated for ${payload.licensee} (${payload.plan})`);\n return true;\n }\n }\n }\n\n _cachedResult = false;\n return false;\n}\n\nexport function getLicenseInfo(): LicensePayload | null {\n isProLicensed();\n return _cachedPayload;\n}\n\nexport function requirePro(featureName: string): boolean {\n if (isProLicensed()) return true;\n\n if (!_warnedOnce) {\n log.warn(\n `Pro features disabled \u2014 set MNEMO_PRO_KEY or MNEMO_LICENSE_TOKEN to enable. ` +\n `Core functionality is fully available. https://m-nemo.ai/pro`,\n );\n _warnedOnce = true;\n }\n if (process.env.MNEMO_DEBUG) {\n log.debug(`Pro feature skipped: ${featureName}`);\n }\n return false;\n}\n\nexport function _resetLicenseCache(): void {\n _cachedResult = null;\n _cachedPayload = null;\n _warnedOnce = false;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLM Client for memory extraction and dedup decisions.
|
|
3
|
+
* Uses OpenAI-compatible API (reuses the embedding provider config).
|
|
4
|
+
*/
|
|
5
|
+
export interface LlmClientConfig {
|
|
6
|
+
apiKey: string;
|
|
7
|
+
model: string;
|
|
8
|
+
baseURL?: string;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
log?: (msg: string) => void;
|
|
11
|
+
}
|
|
12
|
+
export interface LlmClient {
|
|
13
|
+
/** Send a prompt and parse the JSON response. Returns null on failure. */
|
|
14
|
+
completeJson<T>(prompt: string, label?: string): Promise<T | null>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Extract JSON from an LLM response that may be wrapped in markdown fences
|
|
18
|
+
* or contain surrounding text.
|
|
19
|
+
*/
|
|
20
|
+
declare function extractJsonFromResponse(text: string): string | null;
|
|
21
|
+
export declare function createLlmClient(config: LlmClientConfig): LlmClient;
|
|
22
|
+
export { extractJsonFromResponse };
|
|
23
|
+
//# sourceMappingURL=llm-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/llm-client.ts"],"names":[],"mappings":"AACA;;;GAGG;AAIH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,SAAS;IACxB,0EAA0E;IAC1E,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CACpE;AAED;;;GAGG;AACH,iBAAS,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CA0B5D;AAQD,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CA+DlE;AAED,OAAO,EAAE,uBAAuB,EAAE,CAAC"}
|
|
@@ -1,39 +1,11 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
/**
|
|
3
|
-
* LLM Client for memory extraction and dedup decisions.
|
|
4
|
-
* Uses OpenAI-compatible API (reuses the embedding provider config).
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
1
|
import OpenAI from "openai";
|
|
8
|
-
|
|
9
|
-
export interface LlmClientConfig {
|
|
10
|
-
apiKey: string;
|
|
11
|
-
model: string;
|
|
12
|
-
baseURL?: string;
|
|
13
|
-
timeoutMs?: number;
|
|
14
|
-
log?: (msg: string) => void;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface LlmClient {
|
|
18
|
-
/** Send a prompt and parse the JSON response. Returns null on failure. */
|
|
19
|
-
completeJson<T>(prompt: string, label?: string): Promise<T | null>;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Extract JSON from an LLM response that may be wrapped in markdown fences
|
|
24
|
-
* or contain surrounding text.
|
|
25
|
-
*/
|
|
26
|
-
function extractJsonFromResponse(text: string): string | null {
|
|
27
|
-
// Try markdown code fence first (```json ... ``` or ``` ... ```)
|
|
2
|
+
function extractJsonFromResponse(text) {
|
|
28
3
|
const fenceMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
29
4
|
if (fenceMatch) {
|
|
30
5
|
return fenceMatch[1].trim();
|
|
31
6
|
}
|
|
32
|
-
|
|
33
|
-
// Try balanced brace extraction
|
|
34
7
|
const firstBrace = text.indexOf("{");
|
|
35
8
|
if (firstBrace === -1) return null;
|
|
36
|
-
|
|
37
9
|
let depth = 0;
|
|
38
10
|
let lastBrace = -1;
|
|
39
11
|
for (let i = firstBrace; i < text.length; i++) {
|
|
@@ -46,80 +18,75 @@ function extractJsonFromResponse(text: string): string | null {
|
|
|
46
18
|
}
|
|
47
19
|
}
|
|
48
20
|
}
|
|
49
|
-
|
|
50
21
|
if (lastBrace === -1) return null;
|
|
51
22
|
return text.substring(firstBrace, lastBrace + 1);
|
|
52
23
|
}
|
|
53
|
-
|
|
54
|
-
function previewText(value: string, maxLen = 200): string {
|
|
24
|
+
function previewText(value, maxLen = 200) {
|
|
55
25
|
const normalized = value.replace(/\s+/g, " ").trim();
|
|
56
26
|
if (normalized.length <= maxLen) return normalized;
|
|
57
27
|
return `${normalized.slice(0, maxLen - 3)}...`;
|
|
58
28
|
}
|
|
59
|
-
|
|
60
|
-
export function createLlmClient(config: LlmClientConfig): LlmClient {
|
|
29
|
+
function createLlmClient(config) {
|
|
61
30
|
const client = new OpenAI({
|
|
62
31
|
apiKey: config.apiKey,
|
|
63
32
|
baseURL: config.baseURL,
|
|
64
|
-
timeout: config.timeoutMs ??
|
|
33
|
+
timeout: config.timeoutMs ?? 3e4
|
|
34
|
+
});
|
|
35
|
+
const log = config.log ?? (() => {
|
|
65
36
|
});
|
|
66
|
-
const log = config.log ?? (() => {});
|
|
67
|
-
|
|
68
37
|
return {
|
|
69
|
-
async completeJson
|
|
38
|
+
async completeJson(prompt, label = "generic") {
|
|
70
39
|
try {
|
|
71
40
|
const response = await client.chat.completions.create({
|
|
72
41
|
model: config.model,
|
|
73
42
|
messages: [
|
|
74
43
|
{
|
|
75
44
|
role: "system",
|
|
76
|
-
content:
|
|
77
|
-
"You are a memory extraction assistant. Always respond with valid JSON only.",
|
|
45
|
+
content: "You are a memory extraction assistant. Always respond with valid JSON only."
|
|
78
46
|
},
|
|
79
|
-
{ role: "user", content: prompt }
|
|
47
|
+
{ role: "user", content: prompt }
|
|
80
48
|
],
|
|
81
|
-
temperature: 0.1
|
|
49
|
+
temperature: 0.1
|
|
82
50
|
});
|
|
83
|
-
|
|
84
51
|
const raw = response.choices?.[0]?.message?.content;
|
|
85
52
|
if (!raw) {
|
|
86
53
|
log(
|
|
87
|
-
`mnemo: llm-client [${label}] empty response content from model ${config.model}
|
|
54
|
+
`mnemo: llm-client [${label}] empty response content from model ${config.model}`
|
|
88
55
|
);
|
|
89
56
|
return null;
|
|
90
57
|
}
|
|
91
58
|
if (typeof raw !== "string") {
|
|
92
59
|
log(
|
|
93
|
-
`mnemo: llm-client [${label}] non-string response content type=${Array.isArray(raw) ? "array" : typeof raw} from model ${config.model}
|
|
60
|
+
`mnemo: llm-client [${label}] non-string response content type=${Array.isArray(raw) ? "array" : typeof raw} from model ${config.model}`
|
|
94
61
|
);
|
|
95
62
|
return null;
|
|
96
63
|
}
|
|
97
|
-
|
|
98
64
|
const jsonStr = extractJsonFromResponse(raw);
|
|
99
65
|
if (!jsonStr) {
|
|
100
66
|
log(
|
|
101
|
-
`mnemo: llm-client [${label}] no JSON object found (chars=${raw.length}, preview=${JSON.stringify(previewText(raw))})
|
|
67
|
+
`mnemo: llm-client [${label}] no JSON object found (chars=${raw.length}, preview=${JSON.stringify(previewText(raw))})`
|
|
102
68
|
);
|
|
103
69
|
return null;
|
|
104
70
|
}
|
|
105
|
-
|
|
106
71
|
try {
|
|
107
|
-
return JSON.parse(jsonStr)
|
|
72
|
+
return JSON.parse(jsonStr);
|
|
108
73
|
} catch (err) {
|
|
109
74
|
log(
|
|
110
|
-
`mnemo: llm-client [${label}] JSON.parse failed: ${err instanceof Error ? err.message : String(err)} (jsonChars=${jsonStr.length}, jsonPreview=${JSON.stringify(previewText(jsonStr))})
|
|
75
|
+
`mnemo: llm-client [${label}] JSON.parse failed: ${err instanceof Error ? err.message : String(err)} (jsonChars=${jsonStr.length}, jsonPreview=${JSON.stringify(previewText(jsonStr))})`
|
|
111
76
|
);
|
|
112
77
|
return null;
|
|
113
78
|
}
|
|
114
79
|
} catch (err) {
|
|
115
|
-
// Graceful degradation — return null so caller can fall back
|
|
116
80
|
log(
|
|
117
|
-
`mnemo: llm-client [${label}] request failed for model ${config.model}: ${err instanceof Error ? err.message : String(err)}
|
|
81
|
+
`mnemo: llm-client [${label}] request failed for model ${config.model}: ${err instanceof Error ? err.message : String(err)}`
|
|
118
82
|
);
|
|
119
83
|
return null;
|
|
120
84
|
}
|
|
121
|
-
}
|
|
85
|
+
}
|
|
122
86
|
};
|
|
123
87
|
}
|
|
124
|
-
|
|
125
|
-
|
|
88
|
+
export {
|
|
89
|
+
createLlmClient,
|
|
90
|
+
extractJsonFromResponse
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=llm-client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/llm-client.ts"],
|
|
4
|
+
"sourcesContent": ["// SPDX-License-Identifier: MIT\n/**\n * LLM Client for memory extraction and dedup decisions.\n * Uses OpenAI-compatible API (reuses the embedding provider config).\n */\n\nimport OpenAI from \"openai\";\n\nexport interface LlmClientConfig {\n apiKey: string;\n model: string;\n baseURL?: string;\n timeoutMs?: number;\n log?: (msg: string) => void;\n}\n\nexport interface LlmClient {\n /** Send a prompt and parse the JSON response. Returns null on failure. */\n completeJson<T>(prompt: string, label?: string): Promise<T | null>;\n}\n\n/**\n * Extract JSON from an LLM response that may be wrapped in markdown fences\n * or contain surrounding text.\n */\nfunction extractJsonFromResponse(text: string): string | null {\n // Try markdown code fence first (```json ... ``` or ``` ... ```)\n const fenceMatch = text.match(/```(?:json)?\\s*\\n?([\\s\\S]*?)```/);\n if (fenceMatch) {\n return fenceMatch[1].trim();\n }\n\n // Try balanced brace extraction\n const firstBrace = text.indexOf(\"{\");\n if (firstBrace === -1) return null;\n\n let depth = 0;\n let lastBrace = -1;\n for (let i = firstBrace; i < text.length; i++) {\n if (text[i] === \"{\") depth++;\n else if (text[i] === \"}\") {\n depth--;\n if (depth === 0) {\n lastBrace = i;\n break;\n }\n }\n }\n\n if (lastBrace === -1) return null;\n return text.substring(firstBrace, lastBrace + 1);\n}\n\nfunction previewText(value: string, maxLen = 200): string {\n const normalized = value.replace(/\\s+/g, \" \").trim();\n if (normalized.length <= maxLen) return normalized;\n return `${normalized.slice(0, maxLen - 3)}...`;\n}\n\nexport function createLlmClient(config: LlmClientConfig): LlmClient {\n const client = new OpenAI({\n apiKey: config.apiKey,\n baseURL: config.baseURL,\n timeout: config.timeoutMs ?? 30000,\n });\n const log = config.log ?? (() => {});\n\n return {\n async completeJson<T>(prompt: string, label = \"generic\"): Promise<T | null> {\n try {\n const response = await client.chat.completions.create({\n model: config.model,\n messages: [\n {\n role: \"system\",\n content:\n \"You are a memory extraction assistant. Always respond with valid JSON only.\",\n },\n { role: \"user\", content: prompt },\n ],\n temperature: 0.1,\n });\n\n const raw = response.choices?.[0]?.message?.content;\n if (!raw) {\n log(\n `mnemo: llm-client [${label}] empty response content from model ${config.model}`,\n );\n return null;\n }\n if (typeof raw !== \"string\") {\n log(\n `mnemo: llm-client [${label}] non-string response content type=${Array.isArray(raw) ? \"array\" : typeof raw} from model ${config.model}`,\n );\n return null;\n }\n\n const jsonStr = extractJsonFromResponse(raw);\n if (!jsonStr) {\n log(\n `mnemo: llm-client [${label}] no JSON object found (chars=${raw.length}, preview=${JSON.stringify(previewText(raw))})`,\n );\n return null;\n }\n\n try {\n return JSON.parse(jsonStr) as T;\n } catch (err) {\n log(\n `mnemo: llm-client [${label}] JSON.parse failed: ${err instanceof Error ? err.message : String(err)} (jsonChars=${jsonStr.length}, jsonPreview=${JSON.stringify(previewText(jsonStr))})`,\n );\n return null;\n }\n } catch (err) {\n // Graceful degradation \u2014 return null so caller can fall back\n log(\n `mnemo: llm-client [${label}] request failed for model ${config.model}: ${err instanceof Error ? err.message : String(err)}`,\n );\n return null;\n }\n },\n };\n}\n\nexport { extractJsonFromResponse };\n"],
|
|
5
|
+
"mappings": "AAMA,OAAO,YAAY;AAmBnB,SAAS,wBAAwB,MAA6B;AAE5D,QAAM,aAAa,KAAK,MAAM,iCAAiC;AAC/D,MAAI,YAAY;AACd,WAAO,WAAW,CAAC,EAAE,KAAK;AAAA,EAC5B;AAGA,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,MAAI,eAAe,GAAI,QAAO;AAE9B,MAAI,QAAQ;AACZ,MAAI,YAAY;AAChB,WAAS,IAAI,YAAY,IAAI,KAAK,QAAQ,KAAK;AAC7C,QAAI,KAAK,CAAC,MAAM,IAAK;AAAA,aACZ,KAAK,CAAC,MAAM,KAAK;AACxB;AACA,UAAI,UAAU,GAAG;AACf,oBAAY;AACZ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,cAAc,GAAI,QAAO;AAC7B,SAAO,KAAK,UAAU,YAAY,YAAY,CAAC;AACjD;AAEA,SAAS,YAAY,OAAe,SAAS,KAAa;AACxD,QAAM,aAAa,MAAM,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACnD,MAAI,WAAW,UAAU,OAAQ,QAAO;AACxC,SAAO,GAAG,WAAW,MAAM,GAAG,SAAS,CAAC,CAAC;AAC3C;AAEO,SAAS,gBAAgB,QAAoC;AAClE,QAAM,SAAS,IAAI,OAAO;AAAA,IACxB,QAAQ,OAAO;AAAA,IACf,SAAS,OAAO;AAAA,IAChB,SAAS,OAAO,aAAa;AAAA,EAC/B,CAAC;AACD,QAAM,MAAM,OAAO,QAAQ,MAAM;AAAA,EAAC;AAElC,SAAO;AAAA,IACL,MAAM,aAAgB,QAAgB,QAAQ,WAA8B;AAC1E,UAAI;AACF,cAAM,WAAW,MAAM,OAAO,KAAK,YAAY,OAAO;AAAA,UACpD,OAAO,OAAO;AAAA,UACd,UAAU;AAAA,YACR;AAAA,cACE,MAAM;AAAA,cACN,SACE;AAAA,YACJ;AAAA,YACA,EAAE,MAAM,QAAQ,SAAS,OAAO;AAAA,UAClC;AAAA,UACA,aAAa;AAAA,QACf,CAAC;AAED,cAAM,MAAM,SAAS,UAAU,CAAC,GAAG,SAAS;AAC5C,YAAI,CAAC,KAAK;AACR;AAAA,YACE,sBAAsB,KAAK,uCAAuC,OAAO,KAAK;AAAA,UAChF;AACA,iBAAO;AAAA,QACT;AACA,YAAI,OAAO,QAAQ,UAAU;AAC3B;AAAA,YACE,sBAAsB,KAAK,sCAAsC,MAAM,QAAQ,GAAG,IAAI,UAAU,OAAO,GAAG,eAAe,OAAO,KAAK;AAAA,UACvI;AACA,iBAAO;AAAA,QACT;AAEA,cAAM,UAAU,wBAAwB,GAAG;AAC3C,YAAI,CAAC,SAAS;AACZ;AAAA,YACE,sBAAsB,KAAK,iCAAiC,IAAI,MAAM,aAAa,KAAK,UAAU,YAAY,GAAG,CAAC,CAAC;AAAA,UACrH;AACA,iBAAO;AAAA,QACT;AAEA,YAAI;AACF,iBAAO,KAAK,MAAM,OAAO;AAAA,QAC3B,SAAS,KAAK;AACZ;AAAA,YACE,sBAAsB,KAAK,wBAAwB,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC,eAAe,QAAQ,MAAM,iBAAiB,KAAK,UAAU,YAAY,OAAO,CAAC,CAAC;AAAA,UACvL;AACA,iBAAO;AAAA,QACT;AAAA,MACF,SAAS,KAAK;AAEZ;AAAA,UACE,sBAAsB,KAAK,8BAA8B,OAAO,KAAK,KAAK,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC5H;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mnemo Logger — Unified logging interface
|
|
3
|
+
*
|
|
4
|
+
* Replaces scattered console.log/warn/error with a structured logger.
|
|
5
|
+
* Supports log levels, prefixes, and external logger injection.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { log } from "./logger.js";
|
|
9
|
+
* log.info("message");
|
|
10
|
+
* log.warn("something wrong");
|
|
11
|
+
* log.debug("verbose detail"); // only when MNEMO_DEBUG=1
|
|
12
|
+
*/
|
|
13
|
+
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
14
|
+
export interface Logger {
|
|
15
|
+
debug(msg: string, ...args: unknown[]): void;
|
|
16
|
+
info(msg: string, ...args: unknown[]): void;
|
|
17
|
+
warn(msg: string, ...args: unknown[]): void;
|
|
18
|
+
error(msg: string, ...args: unknown[]): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get the current logger instance.
|
|
22
|
+
*/
|
|
23
|
+
export declare const log: Logger;
|
|
24
|
+
/**
|
|
25
|
+
* Replace the default logger with a custom implementation.
|
|
26
|
+
* Useful for integrating with OpenClaw's api.logger or external logging services.
|
|
27
|
+
*/
|
|
28
|
+
export declare function setLogger(logger: Logger): void;
|
|
29
|
+
/**
|
|
30
|
+
* Reset to the default console logger.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resetLogger(): void;
|
|
33
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/logger.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;GAWG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,MAAM;IACrB,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC7C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAC5C,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAC9C;AAwBD;;GAEG;AACH,eAAO,MAAM,GAAG,EAAE,MAKjB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAE9C;AAED;;GAEG;AACH,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const PREFIX = "[mnemo]";
|
|
2
|
+
const isDebug = () => !!process.env.MNEMO_DEBUG;
|
|
3
|
+
const defaultLogger = {
|
|
4
|
+
debug(msg, ...args) {
|
|
5
|
+
if (isDebug()) console.debug(PREFIX, msg, ...args);
|
|
6
|
+
},
|
|
7
|
+
info(msg, ...args) {
|
|
8
|
+
console.log(PREFIX, msg, ...args);
|
|
9
|
+
},
|
|
10
|
+
warn(msg, ...args) {
|
|
11
|
+
console.warn(PREFIX, msg, ...args);
|
|
12
|
+
},
|
|
13
|
+
error(msg, ...args) {
|
|
14
|
+
console.error(PREFIX, msg, ...args);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
let _logger = defaultLogger;
|
|
18
|
+
const log = {
|
|
19
|
+
debug: (msg, ...args) => _logger.debug(msg, ...args),
|
|
20
|
+
info: (msg, ...args) => _logger.info(msg, ...args),
|
|
21
|
+
warn: (msg, ...args) => _logger.warn(msg, ...args),
|
|
22
|
+
error: (msg, ...args) => _logger.error(msg, ...args)
|
|
23
|
+
};
|
|
24
|
+
function setLogger(logger) {
|
|
25
|
+
_logger = logger;
|
|
26
|
+
}
|
|
27
|
+
function resetLogger() {
|
|
28
|
+
_logger = defaultLogger;
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
log,
|
|
32
|
+
resetLogger,
|
|
33
|
+
setLogger
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/logger.ts"],
|
|
4
|
+
"sourcesContent": ["// SPDX-License-Identifier: MIT\n/**\n * Mnemo Logger \u2014 Unified logging interface\n *\n * Replaces scattered console.log/warn/error with a structured logger.\n * Supports log levels, prefixes, and external logger injection.\n *\n * Usage:\n * import { log } from \"./logger.js\";\n * log.info(\"message\");\n * log.warn(\"something wrong\");\n * log.debug(\"verbose detail\"); // only when MNEMO_DEBUG=1\n */\n\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nexport interface Logger {\n debug(msg: string, ...args: unknown[]): void;\n info(msg: string, ...args: unknown[]): void;\n warn(msg: string, ...args: unknown[]): void;\n error(msg: string, ...args: unknown[]): void;\n}\n\nconst PREFIX = \"[mnemo]\";\n\nconst isDebug = () => !!process.env.MNEMO_DEBUG;\n\n/** Default console-based logger */\nconst defaultLogger: Logger = {\n debug(msg, ...args) {\n if (isDebug()) console.debug(PREFIX, msg, ...args);\n },\n info(msg, ...args) {\n console.log(PREFIX, msg, ...args);\n },\n warn(msg, ...args) {\n console.warn(PREFIX, msg, ...args);\n },\n error(msg, ...args) {\n console.error(PREFIX, msg, ...args);\n },\n};\n\nlet _logger: Logger = defaultLogger;\n\n/**\n * Get the current logger instance.\n */\nexport const log: Logger = {\n debug: (msg, ...args) => _logger.debug(msg, ...args),\n info: (msg, ...args) => _logger.info(msg, ...args),\n warn: (msg, ...args) => _logger.warn(msg, ...args),\n error: (msg, ...args) => _logger.error(msg, ...args),\n};\n\n/**\n * Replace the default logger with a custom implementation.\n * Useful for integrating with OpenClaw's api.logger or external logging services.\n */\nexport function setLogger(logger: Logger): void {\n _logger = logger;\n}\n\n/**\n * Reset to the default console logger.\n */\nexport function resetLogger(): void {\n _logger = defaultLogger;\n}\n"],
|
|
5
|
+
"mappings": "AAuBA,MAAM,SAAS;AAEf,MAAM,UAAU,MAAM,CAAC,CAAC,QAAQ,IAAI;AAGpC,MAAM,gBAAwB;AAAA,EAC5B,MAAM,QAAQ,MAAM;AAClB,QAAI,QAAQ,EAAG,SAAQ,MAAM,QAAQ,KAAK,GAAG,IAAI;AAAA,EACnD;AAAA,EACA,KAAK,QAAQ,MAAM;AACjB,YAAQ,IAAI,QAAQ,KAAK,GAAG,IAAI;AAAA,EAClC;AAAA,EACA,KAAK,QAAQ,MAAM;AACjB,YAAQ,KAAK,QAAQ,KAAK,GAAG,IAAI;AAAA,EACnC;AAAA,EACA,MAAM,QAAQ,MAAM;AAClB,YAAQ,MAAM,QAAQ,KAAK,GAAG,IAAI;AAAA,EACpC;AACF;AAEA,IAAI,UAAkB;AAKf,MAAM,MAAc;AAAA,EACzB,OAAO,CAAC,QAAQ,SAAS,QAAQ,MAAM,KAAK,GAAG,IAAI;AAAA,EACnD,MAAM,CAAC,QAAQ,SAAS,QAAQ,KAAK,KAAK,GAAG,IAAI;AAAA,EACjD,MAAM,CAAC,QAAQ,SAAS,QAAQ,KAAK,KAAK,GAAG,IAAI;AAAA,EACjD,OAAO,CAAC,QAAQ,SAAS,QAAQ,MAAM,KAAK,GAAG,IAAI;AACrD;AAMO,SAAS,UAAU,QAAsB;AAC9C,YAAU;AACZ;AAKO,SAAS,cAAoB;AAClC,YAAU;AACZ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server for Mnemo
|
|
3
|
+
*
|
|
4
|
+
* Exposes memory tools (search, store, delete, update, list, stats) over
|
|
5
|
+
* stdio JSON-RPC so Claude Code can call them directly without going through
|
|
6
|
+
* the OpenClaw gateway.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* node --import jiti/register src/mcp-server.ts
|
|
10
|
+
*
|
|
11
|
+
* Register with Claude Code:
|
|
12
|
+
* claude mcp add memory -s user -- node --import jiti/register \
|
|
13
|
+
* /path/to/mnemo/src/mcp-server.ts
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=mcp-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../../src/mcp-server.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;GAaG"}
|