@cybermem/cli 0.14.15 → 0.16.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/dist/commands/install.js
CHANGED
|
@@ -286,7 +286,7 @@ async function install(options) {
|
|
|
286
286
|
}
|
|
287
287
|
const entryPort = isStaging ? "8625" : "8626";
|
|
288
288
|
console.log(chalk_1.default.bold("Next Steps:"));
|
|
289
|
-
console.log(` 1. Open ${chalk_1.default.underline(`http://localhost:${entryPort}
|
|
289
|
+
console.log(` 1. Open ${chalk_1.default.underline(`http://localhost:${entryPort}/`)} to connect your MCP clients`);
|
|
290
290
|
console.log(` 2. Local access is auto-authenticated (no token needed on localhost)`);
|
|
291
291
|
console.log("");
|
|
292
292
|
console.log(chalk_1.default.dim("Local mode is active: No auth required for connections from this device."));
|
|
@@ -61,6 +61,7 @@ services:
|
|
|
61
61
|
CYBERMEM_ENV: ${CYBERMEM_ENV:-prod}
|
|
62
62
|
CYBERMEM_INSTANCE: ${CYBERMEM_INSTANCE:-local}
|
|
63
63
|
CYBERMEM_TAILSCALE: ${CYBERMEM_TAILSCALE:-false}
|
|
64
|
+
OLLAMA_URL: http://ollama:11434
|
|
64
65
|
volumes:
|
|
65
66
|
- ${CYBERMEM_ENV_PATH:-${HOME}/.cybermem/.env}:/.env
|
|
66
67
|
- ${DATA_DIR:-${HOME}/.cybermem/data}:/data
|
|
@@ -68,6 +69,7 @@ services:
|
|
|
68
69
|
depends_on:
|
|
69
70
|
- traefik
|
|
70
71
|
- auth-sidecar
|
|
72
|
+
|
|
71
73
|
# Secrets removed to avoid CI read-only mount issues
|
|
72
74
|
# secrets:
|
|
73
75
|
# - om_api_key
|
|
@@ -179,14 +181,13 @@ services:
|
|
|
179
181
|
|
|
180
182
|
ollama:
|
|
181
183
|
image: ollama/ollama:latest
|
|
184
|
+
profiles: ["ollama"]
|
|
182
185
|
# container_name removed for simultaneity
|
|
183
186
|
ports:
|
|
184
187
|
- "11434:11434"
|
|
185
188
|
volumes:
|
|
186
189
|
- ollama-models:/root/.ollama
|
|
187
190
|
restart: unless-stopped
|
|
188
|
-
profiles:
|
|
189
|
-
- ollama
|
|
190
191
|
|
|
191
192
|
dashboard:
|
|
192
193
|
build:
|
|
@@ -31,17 +31,17 @@ def init_db():
|
|
|
31
31
|
CREATE TABLE IF NOT EXISTS cybermem_stats (
|
|
32
32
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
33
33
|
client_name TEXT NOT NULL,
|
|
34
|
-
|
|
34
|
+
tool TEXT NOT NULL,
|
|
35
35
|
count INTEGER DEFAULT 0,
|
|
36
36
|
errors INTEGER DEFAULT 0,
|
|
37
37
|
last_updated INTEGER NOT NULL,
|
|
38
|
-
UNIQUE(client_name,
|
|
38
|
+
UNIQUE(client_name, tool)
|
|
39
39
|
)
|
|
40
40
|
""")
|
|
41
41
|
|
|
42
42
|
cursor.execute("""
|
|
43
|
-
CREATE INDEX IF NOT EXISTS
|
|
44
|
-
ON cybermem_stats(client_name,
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_cybermem_stats_client_tool
|
|
44
|
+
ON cybermem_stats(client_name, tool)
|
|
45
45
|
""")
|
|
46
46
|
|
|
47
47
|
# Create access log table for detailed request history
|
|
@@ -53,7 +53,7 @@ def init_db():
|
|
|
53
53
|
client_version TEXT,
|
|
54
54
|
method TEXT NOT NULL,
|
|
55
55
|
endpoint TEXT NOT NULL,
|
|
56
|
-
|
|
56
|
+
tool TEXT NOT NULL,
|
|
57
57
|
status TEXT NOT NULL,
|
|
58
58
|
is_error INTEGER DEFAULT 0
|
|
59
59
|
)
|
|
@@ -74,7 +74,7 @@ def init_db():
|
|
|
74
74
|
print(f"[DB] Initialized cybermem tables in {DB_PATH}")
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
def increment_stat(client_name: str,
|
|
77
|
+
def increment_stat(client_name: str, tool: str, is_error: bool = False):
|
|
78
78
|
"""Increment counter in cybermem_stats table"""
|
|
79
79
|
try:
|
|
80
80
|
conn = sqlite3.connect(DB_PATH)
|
|
@@ -86,27 +86,27 @@ def increment_stat(client_name: str, operation: str, is_error: bool = False):
|
|
|
86
86
|
if is_error:
|
|
87
87
|
cursor.execute(
|
|
88
88
|
"""
|
|
89
|
-
INSERT INTO cybermem_stats (client_name,
|
|
89
|
+
INSERT INTO cybermem_stats (client_name, tool, count, errors, last_updated)
|
|
90
90
|
VALUES (?, ?, 1, 1, ?)
|
|
91
|
-
ON CONFLICT(client_name,
|
|
91
|
+
ON CONFLICT(client_name, tool)
|
|
92
92
|
DO UPDATE SET
|
|
93
93
|
count = count + 1,
|
|
94
94
|
errors = errors + 1,
|
|
95
95
|
last_updated = ?
|
|
96
96
|
""",
|
|
97
|
-
[client_name,
|
|
97
|
+
[client_name, tool, ts, ts],
|
|
98
98
|
)
|
|
99
99
|
else:
|
|
100
100
|
cursor.execute(
|
|
101
101
|
"""
|
|
102
|
-
INSERT INTO cybermem_stats (client_name,
|
|
102
|
+
INSERT INTO cybermem_stats (client_name, tool, count, errors, last_updated)
|
|
103
103
|
VALUES (?, ?, 1, 0, ?)
|
|
104
|
-
ON CONFLICT(client_name,
|
|
104
|
+
ON CONFLICT(client_name, tool)
|
|
105
105
|
DO UPDATE SET
|
|
106
106
|
count = count + 1,
|
|
107
107
|
last_updated = ?
|
|
108
108
|
""",
|
|
109
|
-
[client_name,
|
|
109
|
+
[client_name, tool, ts, ts],
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
conn.commit()
|
|
@@ -120,7 +120,7 @@ def log_access(
|
|
|
120
120
|
client_version: str,
|
|
121
121
|
method: str,
|
|
122
122
|
endpoint: str,
|
|
123
|
-
|
|
123
|
+
tool: str,
|
|
124
124
|
status: str,
|
|
125
125
|
is_error: bool,
|
|
126
126
|
):
|
|
@@ -133,7 +133,7 @@ def log_access(
|
|
|
133
133
|
|
|
134
134
|
cursor.execute(
|
|
135
135
|
"""
|
|
136
|
-
INSERT INTO cybermem_access_log (timestamp, client_name, client_version, method, endpoint,
|
|
136
|
+
INSERT INTO cybermem_access_log (timestamp, client_name, client_version, method, endpoint, tool, status, is_error)
|
|
137
137
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
138
138
|
""",
|
|
139
139
|
[
|
|
@@ -142,7 +142,7 @@ def log_access(
|
|
|
142
142
|
client_version,
|
|
143
143
|
method,
|
|
144
144
|
endpoint,
|
|
145
|
-
|
|
145
|
+
tool,
|
|
146
146
|
status,
|
|
147
147
|
1 if is_error else 0,
|
|
148
148
|
],
|
|
@@ -201,29 +201,29 @@ def parse_and_export():
|
|
|
201
201
|
# Remove query params first
|
|
202
202
|
endpoint = path.split("?")[0]
|
|
203
203
|
|
|
204
|
-
# Determine
|
|
204
|
+
# Determine tool type from endpoint BEFORE normalization
|
|
205
205
|
if endpoint == "/memory/add" or endpoint == "/add":
|
|
206
|
-
|
|
206
|
+
tool = "create"
|
|
207
207
|
elif endpoint == "/memory/query" or endpoint == "/query":
|
|
208
|
-
|
|
208
|
+
tool = "read"
|
|
209
209
|
elif endpoint == "/memory/all" or endpoint == "/all":
|
|
210
|
-
|
|
210
|
+
tool = "read" # list_memories
|
|
211
211
|
elif endpoint.startswith("/memory/") and method == "GET":
|
|
212
|
-
|
|
212
|
+
tool = "read" # get by ID
|
|
213
213
|
elif endpoint.startswith("/memory/") and method == "PATCH":
|
|
214
|
-
|
|
214
|
+
tool = "update"
|
|
215
215
|
elif endpoint.startswith("/memory/") and method == "DELETE":
|
|
216
|
-
|
|
216
|
+
tool = "delete"
|
|
217
217
|
elif endpoint.startswith("/mcp"):
|
|
218
|
-
|
|
218
|
+
tool = "mcp" # MCP operations tracked separately
|
|
219
219
|
else:
|
|
220
|
-
|
|
220
|
+
tool = "other"
|
|
221
221
|
|
|
222
222
|
# NOW normalize endpoint to remove IDs (e.g., /memory/123 -> /memory/:id)
|
|
223
223
|
if (
|
|
224
224
|
endpoint.startswith("/memory/")
|
|
225
225
|
and len(endpoint) > 8
|
|
226
|
-
and
|
|
226
|
+
and tool in ["update", "delete"]
|
|
227
227
|
):
|
|
228
228
|
endpoint = "/memory/:id"
|
|
229
229
|
|
|
@@ -234,7 +234,7 @@ def parse_and_export():
|
|
|
234
234
|
|
|
235
235
|
# Write aggregate stats AND audit log ONLY for known clients
|
|
236
236
|
if client_name != "unknown" and "health" not in endpoint:
|
|
237
|
-
increment_stat(client_name,
|
|
237
|
+
increment_stat(client_name, tool, is_error)
|
|
238
238
|
|
|
239
239
|
# Log individual request to access_log
|
|
240
240
|
log_access(
|
|
@@ -242,13 +242,13 @@ def parse_and_export():
|
|
|
242
242
|
client_version,
|
|
243
243
|
method,
|
|
244
244
|
endpoint,
|
|
245
|
-
|
|
245
|
+
tool,
|
|
246
246
|
status,
|
|
247
247
|
is_error,
|
|
248
248
|
)
|
|
249
249
|
|
|
250
250
|
print(
|
|
251
|
-
f"[{time.strftime('%H:%M:%S')}] {client_name}/{client_version} {method} {endpoint} ({
|
|
251
|
+
f"[{time.strftime('%H:%M:%S')}] {client_name}/{client_version} {method} {endpoint} ({tool}) -> {status}"
|
|
252
252
|
)
|
|
253
253
|
|
|
254
254
|
except json.JSONDecodeError:
|
package/package.json
CHANGED
|
@@ -61,6 +61,7 @@ services:
|
|
|
61
61
|
CYBERMEM_ENV: ${CYBERMEM_ENV:-prod}
|
|
62
62
|
CYBERMEM_INSTANCE: ${CYBERMEM_INSTANCE:-local}
|
|
63
63
|
CYBERMEM_TAILSCALE: ${CYBERMEM_TAILSCALE:-false}
|
|
64
|
+
OLLAMA_URL: http://ollama:11434
|
|
64
65
|
volumes:
|
|
65
66
|
- ${CYBERMEM_ENV_PATH:-${HOME}/.cybermem/.env}:/.env
|
|
66
67
|
- ${DATA_DIR:-${HOME}/.cybermem/data}:/data
|
|
@@ -68,6 +69,7 @@ services:
|
|
|
68
69
|
depends_on:
|
|
69
70
|
- traefik
|
|
70
71
|
- auth-sidecar
|
|
72
|
+
|
|
71
73
|
# Secrets removed to avoid CI read-only mount issues
|
|
72
74
|
# secrets:
|
|
73
75
|
# - om_api_key
|
|
@@ -179,14 +181,13 @@ services:
|
|
|
179
181
|
|
|
180
182
|
ollama:
|
|
181
183
|
image: ollama/ollama:latest
|
|
184
|
+
profiles: ["ollama"]
|
|
182
185
|
# container_name removed for simultaneity
|
|
183
186
|
ports:
|
|
184
187
|
- "11434:11434"
|
|
185
188
|
volumes:
|
|
186
189
|
- ollama-models:/root/.ollama
|
|
187
190
|
restart: unless-stopped
|
|
188
|
-
profiles:
|
|
189
|
-
- ollama
|
|
190
191
|
|
|
191
192
|
dashboard:
|
|
192
193
|
build:
|
|
@@ -31,17 +31,17 @@ def init_db():
|
|
|
31
31
|
CREATE TABLE IF NOT EXISTS cybermem_stats (
|
|
32
32
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
33
33
|
client_name TEXT NOT NULL,
|
|
34
|
-
|
|
34
|
+
tool TEXT NOT NULL,
|
|
35
35
|
count INTEGER DEFAULT 0,
|
|
36
36
|
errors INTEGER DEFAULT 0,
|
|
37
37
|
last_updated INTEGER NOT NULL,
|
|
38
|
-
UNIQUE(client_name,
|
|
38
|
+
UNIQUE(client_name, tool)
|
|
39
39
|
)
|
|
40
40
|
""")
|
|
41
41
|
|
|
42
42
|
cursor.execute("""
|
|
43
|
-
CREATE INDEX IF NOT EXISTS
|
|
44
|
-
ON cybermem_stats(client_name,
|
|
43
|
+
CREATE INDEX IF NOT EXISTS idx_cybermem_stats_client_tool
|
|
44
|
+
ON cybermem_stats(client_name, tool)
|
|
45
45
|
""")
|
|
46
46
|
|
|
47
47
|
# Create access log table for detailed request history
|
|
@@ -53,7 +53,7 @@ def init_db():
|
|
|
53
53
|
client_version TEXT,
|
|
54
54
|
method TEXT NOT NULL,
|
|
55
55
|
endpoint TEXT NOT NULL,
|
|
56
|
-
|
|
56
|
+
tool TEXT NOT NULL,
|
|
57
57
|
status TEXT NOT NULL,
|
|
58
58
|
is_error INTEGER DEFAULT 0
|
|
59
59
|
)
|
|
@@ -74,7 +74,7 @@ def init_db():
|
|
|
74
74
|
print(f"[DB] Initialized cybermem tables in {DB_PATH}")
|
|
75
75
|
|
|
76
76
|
|
|
77
|
-
def increment_stat(client_name: str,
|
|
77
|
+
def increment_stat(client_name: str, tool: str, is_error: bool = False):
|
|
78
78
|
"""Increment counter in cybermem_stats table"""
|
|
79
79
|
try:
|
|
80
80
|
conn = sqlite3.connect(DB_PATH)
|
|
@@ -86,27 +86,27 @@ def increment_stat(client_name: str, operation: str, is_error: bool = False):
|
|
|
86
86
|
if is_error:
|
|
87
87
|
cursor.execute(
|
|
88
88
|
"""
|
|
89
|
-
INSERT INTO cybermem_stats (client_name,
|
|
89
|
+
INSERT INTO cybermem_stats (client_name, tool, count, errors, last_updated)
|
|
90
90
|
VALUES (?, ?, 1, 1, ?)
|
|
91
|
-
ON CONFLICT(client_name,
|
|
91
|
+
ON CONFLICT(client_name, tool)
|
|
92
92
|
DO UPDATE SET
|
|
93
93
|
count = count + 1,
|
|
94
94
|
errors = errors + 1,
|
|
95
95
|
last_updated = ?
|
|
96
96
|
""",
|
|
97
|
-
[client_name,
|
|
97
|
+
[client_name, tool, ts, ts],
|
|
98
98
|
)
|
|
99
99
|
else:
|
|
100
100
|
cursor.execute(
|
|
101
101
|
"""
|
|
102
|
-
INSERT INTO cybermem_stats (client_name,
|
|
102
|
+
INSERT INTO cybermem_stats (client_name, tool, count, errors, last_updated)
|
|
103
103
|
VALUES (?, ?, 1, 0, ?)
|
|
104
|
-
ON CONFLICT(client_name,
|
|
104
|
+
ON CONFLICT(client_name, tool)
|
|
105
105
|
DO UPDATE SET
|
|
106
106
|
count = count + 1,
|
|
107
107
|
last_updated = ?
|
|
108
108
|
""",
|
|
109
|
-
[client_name,
|
|
109
|
+
[client_name, tool, ts, ts],
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
conn.commit()
|
|
@@ -120,7 +120,7 @@ def log_access(
|
|
|
120
120
|
client_version: str,
|
|
121
121
|
method: str,
|
|
122
122
|
endpoint: str,
|
|
123
|
-
|
|
123
|
+
tool: str,
|
|
124
124
|
status: str,
|
|
125
125
|
is_error: bool,
|
|
126
126
|
):
|
|
@@ -133,7 +133,7 @@ def log_access(
|
|
|
133
133
|
|
|
134
134
|
cursor.execute(
|
|
135
135
|
"""
|
|
136
|
-
INSERT INTO cybermem_access_log (timestamp, client_name, client_version, method, endpoint,
|
|
136
|
+
INSERT INTO cybermem_access_log (timestamp, client_name, client_version, method, endpoint, tool, status, is_error)
|
|
137
137
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
138
138
|
""",
|
|
139
139
|
[
|
|
@@ -142,7 +142,7 @@ def log_access(
|
|
|
142
142
|
client_version,
|
|
143
143
|
method,
|
|
144
144
|
endpoint,
|
|
145
|
-
|
|
145
|
+
tool,
|
|
146
146
|
status,
|
|
147
147
|
1 if is_error else 0,
|
|
148
148
|
],
|
|
@@ -201,29 +201,29 @@ def parse_and_export():
|
|
|
201
201
|
# Remove query params first
|
|
202
202
|
endpoint = path.split("?")[0]
|
|
203
203
|
|
|
204
|
-
# Determine
|
|
204
|
+
# Determine tool type from endpoint BEFORE normalization
|
|
205
205
|
if endpoint == "/memory/add" or endpoint == "/add":
|
|
206
|
-
|
|
206
|
+
tool = "create"
|
|
207
207
|
elif endpoint == "/memory/query" or endpoint == "/query":
|
|
208
|
-
|
|
208
|
+
tool = "read"
|
|
209
209
|
elif endpoint == "/memory/all" or endpoint == "/all":
|
|
210
|
-
|
|
210
|
+
tool = "read" # list_memories
|
|
211
211
|
elif endpoint.startswith("/memory/") and method == "GET":
|
|
212
|
-
|
|
212
|
+
tool = "read" # get by ID
|
|
213
213
|
elif endpoint.startswith("/memory/") and method == "PATCH":
|
|
214
|
-
|
|
214
|
+
tool = "update"
|
|
215
215
|
elif endpoint.startswith("/memory/") and method == "DELETE":
|
|
216
|
-
|
|
216
|
+
tool = "delete"
|
|
217
217
|
elif endpoint.startswith("/mcp"):
|
|
218
|
-
|
|
218
|
+
tool = "mcp" # MCP operations tracked separately
|
|
219
219
|
else:
|
|
220
|
-
|
|
220
|
+
tool = "other"
|
|
221
221
|
|
|
222
222
|
# NOW normalize endpoint to remove IDs (e.g., /memory/123 -> /memory/:id)
|
|
223
223
|
if (
|
|
224
224
|
endpoint.startswith("/memory/")
|
|
225
225
|
and len(endpoint) > 8
|
|
226
|
-
and
|
|
226
|
+
and tool in ["update", "delete"]
|
|
227
227
|
):
|
|
228
228
|
endpoint = "/memory/:id"
|
|
229
229
|
|
|
@@ -234,7 +234,7 @@ def parse_and_export():
|
|
|
234
234
|
|
|
235
235
|
# Write aggregate stats AND audit log ONLY for known clients
|
|
236
236
|
if client_name != "unknown" and "health" not in endpoint:
|
|
237
|
-
increment_stat(client_name,
|
|
237
|
+
increment_stat(client_name, tool, is_error)
|
|
238
238
|
|
|
239
239
|
# Log individual request to access_log
|
|
240
240
|
log_access(
|
|
@@ -242,13 +242,13 @@ def parse_and_export():
|
|
|
242
242
|
client_version,
|
|
243
243
|
method,
|
|
244
244
|
endpoint,
|
|
245
|
-
|
|
245
|
+
tool,
|
|
246
246
|
status,
|
|
247
247
|
is_error,
|
|
248
248
|
)
|
|
249
249
|
|
|
250
250
|
print(
|
|
251
|
-
f"[{time.strftime('%H:%M:%S')}] {client_name}/{client_version} {method} {endpoint} ({
|
|
251
|
+
f"[{time.strftime('%H:%M:%S')}] {client_name}/{client_version} {method} {endpoint} ({tool}) -> {status}"
|
|
252
252
|
)
|
|
253
253
|
|
|
254
254
|
except json.JSONDecodeError:
|