@memclaw/memclaw 0.9.13 → 0.9.17

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.
@@ -1,44 +1,63 @@
1
- "use strict";
1
+ 'use strict';
2
2
  /**
3
3
  * Configuration management for MemClaw
4
4
  *
5
5
  * Handles platform-specific config paths, config file generation,
6
6
  * and auto-opening config files for user editing.
7
7
  */
8
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
- if (k2 === undefined) k2 = k;
10
- var desc = Object.getOwnPropertyDescriptor(m, k);
11
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
- desc = { enumerable: true, get: function() { return m[k]; } };
13
- }
14
- Object.defineProperty(o, k2, desc);
15
- }) : (function(o, m, k, k2) {
16
- if (k2 === undefined) k2 = k;
17
- o[k2] = m[k];
18
- }));
19
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
- Object.defineProperty(o, "default", { enumerable: true, value: v });
21
- }) : function(o, v) {
22
- o["default"] = v;
23
- });
24
- var __importStar = (this && this.__importStar) || (function () {
25
- var ownKeys = function(o) {
26
- ownKeys = Object.getOwnPropertyNames || function (o) {
27
- var ar = [];
28
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
- return ar;
30
- };
31
- return ownKeys(o);
32
- };
33
- return function (mod) {
34
- if (mod && mod.__esModule) return mod;
35
- var result = {};
36
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
- __setModuleDefault(result, mod);
38
- return result;
39
- };
40
- })();
41
- Object.defineProperty(exports, "__esModule", { value: true });
8
+ var __createBinding =
9
+ (this && this.__createBinding) ||
10
+ (Object.create
11
+ ? function (o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ('get' in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = {
16
+ enumerable: true,
17
+ get: function () {
18
+ return m[k];
19
+ }
20
+ };
21
+ }
22
+ Object.defineProperty(o, k2, desc);
23
+ }
24
+ : function (o, m, k, k2) {
25
+ if (k2 === undefined) k2 = k;
26
+ o[k2] = m[k];
27
+ });
28
+ var __setModuleDefault =
29
+ (this && this.__setModuleDefault) ||
30
+ (Object.create
31
+ ? function (o, v) {
32
+ Object.defineProperty(o, 'default', { enumerable: true, value: v });
33
+ }
34
+ : function (o, v) {
35
+ o['default'] = v;
36
+ });
37
+ var __importStar =
38
+ (this && this.__importStar) ||
39
+ (function () {
40
+ var ownKeys = function (o) {
41
+ ownKeys =
42
+ Object.getOwnPropertyNames ||
43
+ function (o) {
44
+ var ar = [];
45
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
46
+ return ar;
47
+ };
48
+ return ownKeys(o);
49
+ };
50
+ return function (mod) {
51
+ if (mod && mod.__esModule) return mod;
52
+ var result = {};
53
+ if (mod != null)
54
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++)
55
+ if (k[i] !== 'default') __createBinding(result, mod, k[i]);
56
+ __setModuleDefault(result, mod);
57
+ return result;
58
+ };
59
+ })();
60
+ Object.defineProperty(exports, '__esModule', { value: true });
42
61
  exports.getDataDir = getDataDir;
43
62
  exports.getConfigPath = getConfigPath;
44
63
  exports.generateConfigTemplate = generateConfigTemplate;
@@ -48,28 +67,29 @@ exports.parseConfig = parseConfig;
48
67
  exports.validateConfig = validateConfig;
49
68
  exports.updateConfigFromPlugin = updateConfigFromPlugin;
50
69
  exports.mergeConfigWithPlugin = mergeConfigWithPlugin;
51
- const fs = __importStar(require("fs"));
52
- const path = __importStar(require("path"));
53
- const os = __importStar(require("os"));
54
- const child_process_1 = require("child_process");
70
+ const fs = __importStar(require('fs'));
71
+ const path = __importStar(require('path'));
72
+ const os = __importStar(require('os'));
73
+ const child_process_1 = require('child_process');
55
74
  // Platform-specific paths
56
75
  function getDataDir() {
57
- const platform = process.platform;
58
- if (platform === 'win32') {
59
- return path.join(process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), 'memclaw');
60
- }
61
- else if (platform === 'darwin') {
62
- return path.join(os.homedir(), 'Library', 'Application Support', 'memclaw');
63
- }
64
- else {
65
- return path.join(os.homedir(), '.local', 'share', 'memclaw');
66
- }
76
+ const platform = process.platform;
77
+ if (platform === 'win32') {
78
+ return path.join(
79
+ process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'),
80
+ 'memclaw'
81
+ );
82
+ } else if (platform === 'darwin') {
83
+ return path.join(os.homedir(), 'Library', 'Application Support', 'memclaw');
84
+ } else {
85
+ return path.join(os.homedir(), '.local', 'share', 'memclaw');
86
+ }
67
87
  }
68
88
  function getConfigPath() {
69
- return path.join(getDataDir(), 'config.toml');
89
+ return path.join(getDataDir(), 'config.toml');
70
90
  }
71
91
  function generateConfigTemplate() {
72
- return `# MemClaw Configuration
92
+ return `# MemClaw Configuration
73
93
  #
74
94
  # This file was auto-generated. Please fill in the required values below.
75
95
  # All sections are required - missing sections will cause config to be ignored.
@@ -100,6 +120,7 @@ timeout_secs = 30
100
120
  [server]
101
121
  host = "localhost"
102
122
  port = 8085
123
+ cors_origins = ["*"]
103
124
 
104
125
  # Logging Configuration
105
126
  [logging]
@@ -113,230 +134,222 @@ enable_intent_analysis = false
113
134
  `;
114
135
  }
115
136
  function ensureConfigExists() {
116
- const dataDir = getDataDir();
117
- const configPath = getConfigPath();
118
- if (!fs.existsSync(dataDir)) {
119
- fs.mkdirSync(dataDir, { recursive: true });
120
- }
121
- if (!fs.existsSync(configPath)) {
122
- const template = generateConfigTemplate();
123
- fs.writeFileSync(configPath, template, 'utf-8');
124
- return { created: true, path: configPath };
125
- }
126
- return { created: false, path: configPath };
137
+ const dataDir = getDataDir();
138
+ const configPath = getConfigPath();
139
+ if (!fs.existsSync(dataDir)) {
140
+ fs.mkdirSync(dataDir, { recursive: true });
141
+ }
142
+ if (!fs.existsSync(configPath)) {
143
+ const template = generateConfigTemplate();
144
+ fs.writeFileSync(configPath, template, 'utf-8');
145
+ return { created: true, path: configPath };
146
+ }
147
+ return { created: false, path: configPath };
127
148
  }
128
149
  function openConfigFile(configPath) {
129
- return new Promise((resolve, reject) => {
130
- const platform = process.platform;
131
- let command;
132
- let args = [];
133
- if (platform === 'win32') {
134
- command = 'cmd';
135
- args = ['/c', 'start', '""', configPath];
136
- }
137
- else if (platform === 'darwin') {
138
- command = 'open';
139
- args = [configPath];
140
- }
141
- else {
142
- command = 'xdg-open';
143
- args = [configPath];
144
- }
145
- const proc = (0, child_process_1.spawn)(command, args, { detached: true, stdio: 'ignore' });
146
- proc.on('error', (err) => {
147
- reject(err);
148
- });
149
- proc.unref();
150
- resolve();
151
- });
150
+ return new Promise((resolve, reject) => {
151
+ const platform = process.platform;
152
+ let command;
153
+ let args = [];
154
+ if (platform === 'win32') {
155
+ command = 'cmd';
156
+ args = ['/c', 'start', '""', configPath];
157
+ } else if (platform === 'darwin') {
158
+ command = 'open';
159
+ args = [configPath];
160
+ } else {
161
+ command = 'xdg-open';
162
+ args = [configPath];
163
+ }
164
+ const proc = (0, child_process_1.spawn)(command, args, { detached: true, stdio: 'ignore' });
165
+ proc.on('error', (err) => {
166
+ reject(err);
167
+ });
168
+ proc.unref();
169
+ resolve();
170
+ });
152
171
  }
153
172
  function parseConfig(configPath) {
154
- const content = fs.readFileSync(configPath, 'utf-8');
155
- const config = {};
156
- let currentSection = '';
157
- for (const line of content.split('\n')) {
158
- const trimmed = line.trim();
159
- // Skip comments and empty lines
160
- if (trimmed.startsWith('#') || trimmed === '')
161
- continue;
162
- // Section header
163
- const sectionMatch = trimmed.match(/^\[(\w+)\]$/);
164
- if (sectionMatch) {
165
- currentSection = sectionMatch[1];
166
- config[currentSection] = {};
167
- continue;
168
- }
169
- // Key-value pair
170
- const kvMatch = trimmed.match(/^(\w+)\s*=\s*"([^"]*)"(?:\s*$|\s*#)/) ||
171
- trimmed.match(/^(\w+)\s*=\s*(\d+(?:\.\d+)?)(?:\s*$|\s*#)/) ||
172
- trimmed.match(/^(\w+)\s*=\s*(true|false)(?:\s*$|\s*#)/);
173
- if (kvMatch && currentSection) {
174
- const key = kvMatch[1];
175
- let value = kvMatch[2];
176
- // Convert to appropriate type
177
- if (value === 'true')
178
- value = true;
179
- else if (value === 'false')
180
- value = false;
181
- else if (/^\d+$/.test(value))
182
- value = parseInt(value, 10);
183
- else if (/^\d+\.\d+$/.test(value))
184
- value = parseFloat(value);
185
- config[currentSection] = config[currentSection] || {};
186
- config[currentSection][key] = value;
187
- }
188
- }
189
- // Apply defaults
190
- return {
191
- qdrant: {
192
- url: 'http://localhost:6334',
193
- collection_name: 'memclaw',
194
- timeout_secs: 30,
195
- ...(config.qdrant || {})
196
- },
197
- llm: {
198
- api_base_url: 'https://api.openai.com/v1',
199
- api_key: '',
200
- model_efficient: 'gpt-5-mini',
201
- temperature: 0.1,
202
- max_tokens: 4096,
203
- ...(config.llm || {})
204
- },
205
- embedding: {
206
- api_base_url: 'https://api.openai.com/v1',
207
- api_key: '',
208
- model_name: 'text-embedding-3-small',
209
- batch_size: 10,
210
- timeout_secs: 30,
211
- ...(config.embedding || {})
212
- },
213
- server: {
214
- host: 'localhost',
215
- port: 8085,
216
- ...(config.server || {})
217
- },
218
- logging: {
219
- enabled: false,
220
- log_directory: 'logs',
221
- level: 'info',
222
- ...(config.logging || {})
223
- },
224
- cortex: {
225
- enable_intent_analysis: false,
226
- ...(config.cortex || {})
227
- }
228
- };
173
+ const content = fs.readFileSync(configPath, 'utf-8');
174
+ const config = {};
175
+ let currentSection = '';
176
+ for (const line of content.split('\n')) {
177
+ const trimmed = line.trim();
178
+ // Skip comments and empty lines
179
+ if (trimmed.startsWith('#') || trimmed === '') continue;
180
+ // Section header
181
+ const sectionMatch = trimmed.match(/^\[(\w+)\]$/);
182
+ if (sectionMatch) {
183
+ currentSection = sectionMatch[1];
184
+ config[currentSection] = {};
185
+ continue;
186
+ }
187
+ // Key-value pair
188
+ const kvMatch =
189
+ trimmed.match(/^(\w+)\s*=\s*"([^"]*)"(?:\s*$|\s*#)/) ||
190
+ trimmed.match(/^(\w+)\s*=\s*(\d+(?:\.\d+)?)(?:\s*$|\s*#)/) ||
191
+ trimmed.match(/^(\w+)\s*=\s*(true|false)(?:\s*$|\s*#)/);
192
+ if (kvMatch && currentSection) {
193
+ const key = kvMatch[1];
194
+ let value = kvMatch[2];
195
+ // Convert to appropriate type
196
+ if (value === 'true') value = true;
197
+ else if (value === 'false') value = false;
198
+ else if (/^\d+$/.test(value)) value = parseInt(value, 10);
199
+ else if (/^\d+\.\d+$/.test(value)) value = parseFloat(value);
200
+ config[currentSection] = config[currentSection] || {};
201
+ config[currentSection][key] = value;
202
+ }
203
+ }
204
+ // Apply defaults
205
+ return {
206
+ qdrant: {
207
+ url: 'http://localhost:6334',
208
+ collection_name: 'memclaw',
209
+ timeout_secs: 30,
210
+ ...(config.qdrant || {})
211
+ },
212
+ llm: {
213
+ api_base_url: 'https://api.openai.com/v1',
214
+ api_key: '',
215
+ model_efficient: 'gpt-5-mini',
216
+ temperature: 0.1,
217
+ max_tokens: 4096,
218
+ ...(config.llm || {})
219
+ },
220
+ embedding: {
221
+ api_base_url: 'https://api.openai.com/v1',
222
+ api_key: '',
223
+ model_name: 'text-embedding-3-small',
224
+ batch_size: 10,
225
+ timeout_secs: 30,
226
+ ...(config.embedding || {})
227
+ },
228
+ server: {
229
+ host: 'localhost',
230
+ port: 8085,
231
+ ...(config.server || {})
232
+ },
233
+ logging: {
234
+ enabled: false,
235
+ log_directory: 'logs',
236
+ level: 'info',
237
+ ...(config.logging || {})
238
+ },
239
+ cortex: {
240
+ enable_intent_analysis: false,
241
+ ...(config.cortex || {})
242
+ }
243
+ };
229
244
  }
230
245
  function validateConfig(config) {
231
- const errors = [];
232
- if (!config.llm.api_key || config.llm.api_key === '') {
233
- errors.push('llm.api_key is required');
234
- }
235
- if (!config.embedding.api_key || config.embedding.api_key === '') {
236
- // Allow using llm.api_key for embedding if not specified
237
- if (config.llm.api_key && config.llm.api_key !== '') {
238
- config.embedding.api_key = config.llm.api_key;
239
- }
240
- else {
241
- errors.push('embedding.api_key is required');
242
- }
243
- }
244
- return {
245
- valid: errors.length === 0,
246
- errors
247
- };
246
+ const errors = [];
247
+ if (!config.llm.api_key || config.llm.api_key === '') {
248
+ errors.push('llm.api_key is required');
249
+ }
250
+ if (!config.embedding.api_key || config.embedding.api_key === '') {
251
+ // Allow using llm.api_key for embedding if not specified
252
+ if (config.llm.api_key && config.llm.api_key !== '') {
253
+ config.embedding.api_key = config.llm.api_key;
254
+ } else {
255
+ errors.push('embedding.api_key is required');
256
+ }
257
+ }
258
+ return {
259
+ valid: errors.length === 0,
260
+ errors
261
+ };
248
262
  }
249
263
  /**
250
264
  * Update config.toml with values from OpenClaw plugin config
251
265
  * Only updates fields that are provided (non-empty) in pluginConfig
252
266
  */
253
267
  function updateConfigFromPlugin(pluginConfig) {
254
- const configPath = getConfigPath();
255
- // Ensure config file exists
256
- ensureConfigExists();
257
- // Parse existing config
258
- const existingConfig = parseConfig(configPath);
259
- // Track if any changes were made
260
- let updated = false;
261
- // Build updated config sections
262
- const updates = [];
263
- // LLM config updates
264
- if (pluginConfig.llmApiKey && pluginConfig.llmApiKey !== '') {
265
- updates.push({ section: 'llm', key: 'api_key', value: pluginConfig.llmApiKey });
266
- updated = true;
267
- }
268
- if (pluginConfig.llmApiBaseUrl && pluginConfig.llmApiBaseUrl !== '') {
269
- updates.push({ section: 'llm', key: 'api_base_url', value: pluginConfig.llmApiBaseUrl });
270
- updated = true;
271
- }
272
- if (pluginConfig.llmModel && pluginConfig.llmModel !== '') {
273
- updates.push({ section: 'llm', key: 'model_efficient', value: pluginConfig.llmModel });
274
- updated = true;
275
- }
276
- // Embedding config updates
277
- if (pluginConfig.embeddingApiKey && pluginConfig.embeddingApiKey !== '') {
278
- updates.push({ section: 'embedding', key: 'api_key', value: pluginConfig.embeddingApiKey });
279
- updated = true;
280
- }
281
- if (pluginConfig.embeddingApiBaseUrl && pluginConfig.embeddingApiBaseUrl !== '') {
282
- updates.push({
283
- section: 'embedding',
284
- key: 'api_base_url',
285
- value: pluginConfig.embeddingApiBaseUrl
286
- });
287
- updated = true;
288
- }
289
- if (pluginConfig.embeddingModel && pluginConfig.embeddingModel !== '') {
290
- updates.push({ section: 'embedding', key: 'model_name', value: pluginConfig.embeddingModel });
291
- updated = true;
292
- }
293
- if (!updated) {
294
- return { updated: false, path: configPath };
295
- }
296
- // Read current content
297
- let content = fs.readFileSync(configPath, 'utf-8');
298
- // Apply each update
299
- for (const { section, key, value } of updates) {
300
- // Escape value for TOML string
301
- const escapedValue = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
302
- // Pattern to match the key in the correct section
303
- // This handles both existing keys and missing keys
304
- const sectionPattern = new RegExp(`(\\[${section}\\][^\\[]*?)(${key}\\s*=\\s*)"[^"]*"`, 's');
305
- const keyExistsInSection = sectionPattern.test(content);
306
- if (keyExistsInSection) {
307
- // Update existing key
308
- content = content.replace(sectionPattern, `$1$2"${escapedValue}"`);
309
- }
310
- else {
311
- // Add key to section
312
- const sectionStartPattern = new RegExp(`(\\[${section}\\]\\n)`, '');
313
- if (sectionStartPattern.test(content)) {
314
- content = content.replace(sectionStartPattern, `$1${key} = "${escapedValue}"\n`);
315
- }
316
- }
317
- }
318
- // Write updated content
319
- fs.writeFileSync(configPath, content, 'utf-8');
320
- return { updated: true, path: configPath };
268
+ const configPath = getConfigPath();
269
+ // Ensure config file exists
270
+ ensureConfigExists();
271
+ // Parse existing config
272
+ const existingConfig = parseConfig(configPath);
273
+ // Track if any changes were made
274
+ let updated = false;
275
+ // Build updated config sections
276
+ const updates = [];
277
+ // LLM config updates
278
+ if (pluginConfig.llmApiKey && pluginConfig.llmApiKey !== '') {
279
+ updates.push({ section: 'llm', key: 'api_key', value: pluginConfig.llmApiKey });
280
+ updated = true;
281
+ }
282
+ if (pluginConfig.llmApiBaseUrl && pluginConfig.llmApiBaseUrl !== '') {
283
+ updates.push({ section: 'llm', key: 'api_base_url', value: pluginConfig.llmApiBaseUrl });
284
+ updated = true;
285
+ }
286
+ if (pluginConfig.llmModel && pluginConfig.llmModel !== '') {
287
+ updates.push({ section: 'llm', key: 'model_efficient', value: pluginConfig.llmModel });
288
+ updated = true;
289
+ }
290
+ // Embedding config updates
291
+ if (pluginConfig.embeddingApiKey && pluginConfig.embeddingApiKey !== '') {
292
+ updates.push({ section: 'embedding', key: 'api_key', value: pluginConfig.embeddingApiKey });
293
+ updated = true;
294
+ }
295
+ if (pluginConfig.embeddingApiBaseUrl && pluginConfig.embeddingApiBaseUrl !== '') {
296
+ updates.push({
297
+ section: 'embedding',
298
+ key: 'api_base_url',
299
+ value: pluginConfig.embeddingApiBaseUrl
300
+ });
301
+ updated = true;
302
+ }
303
+ if (pluginConfig.embeddingModel && pluginConfig.embeddingModel !== '') {
304
+ updates.push({ section: 'embedding', key: 'model_name', value: pluginConfig.embeddingModel });
305
+ updated = true;
306
+ }
307
+ if (!updated) {
308
+ return { updated: false, path: configPath };
309
+ }
310
+ // Read current content
311
+ let content = fs.readFileSync(configPath, 'utf-8');
312
+ // Apply each update
313
+ for (const { section, key, value } of updates) {
314
+ // Escape value for TOML string
315
+ const escapedValue = value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
316
+ // Pattern to match the key in the correct section
317
+ // This handles both existing keys and missing keys
318
+ const sectionPattern = new RegExp(`(\\[${section}\\][^\\[]*?)(${key}\\s*=\\s*)"[^"]*"`, 's');
319
+ const keyExistsInSection = sectionPattern.test(content);
320
+ if (keyExistsInSection) {
321
+ // Update existing key
322
+ content = content.replace(sectionPattern, `$1$2"${escapedValue}"`);
323
+ } else {
324
+ // Add key to section
325
+ const sectionStartPattern = new RegExp(`(\\[${section}\\]\\n)`, '');
326
+ if (sectionStartPattern.test(content)) {
327
+ content = content.replace(sectionStartPattern, `$1${key} = "${escapedValue}"\n`);
328
+ }
329
+ }
330
+ }
331
+ // Write updated content
332
+ fs.writeFileSync(configPath, content, 'utf-8');
333
+ return { updated: true, path: configPath };
321
334
  }
322
335
  /**
323
336
  * Merge plugin config with file config, preferring plugin config values
324
337
  */
325
338
  function mergeConfigWithPlugin(fileConfig, pluginConfig) {
326
- return {
327
- ...fileConfig,
328
- llm: {
329
- ...fileConfig.llm,
330
- api_base_url: pluginConfig.llmApiBaseUrl || fileConfig.llm.api_base_url,
331
- api_key: pluginConfig.llmApiKey || fileConfig.llm.api_key,
332
- model_efficient: pluginConfig.llmModel || fileConfig.llm.model_efficient
333
- },
334
- embedding: {
335
- ...fileConfig.embedding,
336
- api_base_url: pluginConfig.embeddingApiBaseUrl || fileConfig.embedding.api_base_url,
337
- api_key: pluginConfig.embeddingApiKey || fileConfig.embedding.api_key,
338
- model_name: pluginConfig.embeddingModel || fileConfig.embedding.model_name
339
- }
340
- };
339
+ return {
340
+ ...fileConfig,
341
+ llm: {
342
+ ...fileConfig.llm,
343
+ api_base_url: pluginConfig.llmApiBaseUrl || fileConfig.llm.api_base_url,
344
+ api_key: pluginConfig.llmApiKey || fileConfig.llm.api_key,
345
+ model_efficient: pluginConfig.llmModel || fileConfig.llm.model_efficient
346
+ },
347
+ embedding: {
348
+ ...fileConfig.embedding,
349
+ api_base_url: pluginConfig.embeddingApiBaseUrl || fileConfig.embedding.api_base_url,
350
+ api_key: pluginConfig.embeddingApiKey || fileConfig.embedding.api_key,
351
+ model_name: pluginConfig.embeddingModel || fileConfig.embedding.model_name
352
+ }
353
+ };
341
354
  }
342
- //# sourceMappingURL=config.js.map
355
+ //# sourceMappingURL=config.js.map
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "id": "memclaw",
3
3
  "name": "MemClaw",
4
- "version": "0.9.13",
4
+ "version": "0.9.17",
5
5
  "description": "Layered semantic memory for OpenClaw with L0/L1/L2 tiered retrieval, easy setup, and migration from native memory",
6
6
  "kind": "memory",
7
- "skills": ["skills/memclaw"],
7
+ "skills": ["skills/memclaw", "skills/memclaw-maintance"],
8
8
  "platforms": ["darwin-arm64", "win32-x64"],
9
9
  "osRestriction": ["darwin-arm64", "win32-x64"],
10
10
  "configSchema": {
@@ -85,14 +85,7 @@
85
85
  "default": "text-embedding-3-small"
86
86
  }
87
87
  },
88
- "required": [
89
- "llmApiKey",
90
- "embeddingApiKey",
91
- "llmApiBaseUrl",
92
- "llmModel",
93
- "embeddingApiBaseUrl",
94
- "embeddingModel"
95
- ]
88
+ "required": []
96
89
  },
97
90
  "uiHints": {
98
91
  "serviceUrl": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memclaw/memclaw",
3
- "version": "0.9.13",
3
+ "version": "0.9.17",
4
4
  "description": "MemClaw - The Cortex Memory plugin for OpenClaw. Layered semantic memory for OpenClaw with easy setup and migration",
5
5
  "homepage": "https://github.com/sopaco/cortex-mem",
6
6
  "repository": {
@@ -36,7 +36,8 @@
36
36
  "dist/index.js"
37
37
  ],
38
38
  "skills": [
39
- "skills/memclaw"
39
+ "skills/memclaw",
40
+ "skills/memclaw-maintance"
40
41
  ]
41
42
  },
42
43
  "devDependencies": {
@@ -145,6 +145,7 @@ timeout_secs = 30
145
145
  [server]
146
146
  host = "localhost"
147
147
  port = 8085
148
+ cors_origins = ["*"]
148
149
 
149
150
  # Logging Configuration
150
151
  [logging]
@@ -174,11 +175,6 @@ Check that Qdrant and cortex-mem-service are accessible:
174
175
 
175
176
  If `autoStartServices` is `true` in plugin config, MemClaw will start Qdrant automatically.
176
177
 
177
- To start manually, run the Qdrant binary from the platform package with:
178
- - `--storage-path` pointing to a storage directory
179
- - `--http-port 6333`
180
- - `--grpc-port 6334`
181
-
182
178
  **Starting cortex-mem-service:**
183
179
 
184
180
  **CRITICAL**: cortex-mem-service MUST be started with `--data-dir` flag pointing to the directory containing `config.toml`.