neoagent 2.2.1-beta.7 → 2.3.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.
@@ -0,0 +1,409 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+ const readline = require('readline');
5
+ const { parseEnv } = require('../runtime/env');
6
+ const { ENV_FILE, AGENT_DATA_DIR, DATA_DIR } = require('../runtime/paths');
7
+
8
+ const HOME_DIR = os.homedir();
9
+
10
+ const OPENCLAW_PATHS = {
11
+ config: path.join(HOME_DIR, '.openclaw', 'openclaw.json'),
12
+ workspace: path.join(HOME_DIR, '.openclaw', 'workspace'),
13
+ skills: path.join(HOME_DIR, '.openclaw', 'skills'),
14
+ soul: path.join(HOME_DIR, '.openclaw', 'workspace', 'SOUL.md'),
15
+ memory: path.join(HOME_DIR, '.openclaw', 'workspace', 'MEMORY.md'),
16
+ user: path.join(HOME_DIR, '.openclaw', 'workspace', 'USER.md'),
17
+ agents: path.join(HOME_DIR, '.openclaw', 'agents'),
18
+ env: path.join(HOME_DIR, '.openclaw', '.env'),
19
+ legacyConfig: path.join(HOME_DIR, '.clawdbot', 'config.json')
20
+ };
21
+
22
+ const HERMES_PATHS = {
23
+ config: path.join(HOME_DIR, '.hermes', 'config.yaml'),
24
+ env: path.join(HOME_DIR, '.hermes', '.env'),
25
+ skills: path.join(HOME_DIR, '.hermes', 'skills'),
26
+ memories: path.join(HOME_DIR, '.hermes', 'memories'),
27
+ memory: path.join(HOME_DIR, '.hermes', 'memories', 'MEMORY.md'),
28
+ user: path.join(HOME_DIR, '.hermes', 'memories', 'USER.md'),
29
+ logs: path.join(HOME_DIR, '.hermes', 'logs')
30
+ };
31
+
32
+ const NEOAGENT_SKILLS_DIR = path.join(AGENT_DATA_DIR, 'skills');
33
+ const NEOAGENT_MEMORY_DIR = path.join(AGENT_DATA_DIR, 'memory');
34
+
35
+ const API_KEY_NAMES = [
36
+ 'ANTHROPIC_API_KEY', 'OPENAI_API_KEY', 'XAI_API_KEY', 'GOOGLE_AI_KEY',
37
+ 'MINIMAX_API_KEY', 'BRAVE_SEARCH_API_KEY', 'DEEPGRAM_API_KEY',
38
+ 'TELEGRAM_BOT_TOKEN', 'OPENROUTER_API_KEY', 'ELEVENLABS_API_KEY',
39
+ 'VOICE_TOOLS_OPENAI_KEY', 'SLACK_BOT_TOKEN', 'DISCORD_BOT_TOKEN'
40
+ ];
41
+
42
+ function detectSourceAgents() {
43
+ const detected = { openclaw: false, hermes: false };
44
+
45
+ if (fs.existsSync(OPENCLAW_PATHS.config) || fs.existsSync(OPENCLAW_PATHS.legacyConfig)) {
46
+ detected.openclaw = true;
47
+ }
48
+ if (fs.existsSync(HERMES_PATHS.config) || fs.existsSync(HERMES_PATHS.env)) {
49
+ detected.hermes = true;
50
+ }
51
+
52
+ return detected;
53
+ }
54
+
55
+ function scanOpenClaw() {
56
+ const scan = { skills: [], memories: [], apiKeys: {}, connections: [] };
57
+
58
+ if (fs.existsSync(OPENCLAW_PATHS.skills)) {
59
+ const files = fs.readdirSync(OPENCLAW_PATHS.skills).filter(f => f.endsWith('.md'));
60
+ scan.skills = files.map(f => ({ name: f.replace('.md', ''), path: path.join(OPENCLAW_PATHS.skills, f) }));
61
+ }
62
+
63
+ for (const [key, filePath] of Object.entries({
64
+ soul: OPENCLAW_PATHS.soul,
65
+ memory: OPENCLAW_PATHS.memory,
66
+ user: OPENCLAW_PATHS.user
67
+ })) {
68
+ if (fs.existsSync(filePath)) {
69
+ scan.memories.push({ type: key, path: filePath });
70
+ }
71
+ }
72
+
73
+ if (fs.existsSync(OPENCLAW_PATHS.env)) {
74
+ const envMap = parseEnv(fs.readFileSync(OPENCLAW_PATHS.env, 'utf8'));
75
+ for (const [key, value] of envMap.entries()) {
76
+ if (API_KEY_NAMES.includes(key) && value) {
77
+ scan.apiKeys[key] = value;
78
+ }
79
+ }
80
+ }
81
+
82
+ return scan;
83
+ }
84
+
85
+ function scanHermes() {
86
+ const scan = { skills: [], memories: [], apiKeys: {}, connections: [] };
87
+
88
+ if (fs.existsSync(HERMES_PATHS.skills)) {
89
+ const files = fs.readdirSync(HERMES_PATHS.skills).filter(f => f.endsWith('.md'));
90
+ scan.skills = files.map(f => ({ name: f.replace('.md', ''), path: path.join(HERMES_PATHS.skills, f) }));
91
+ }
92
+
93
+ for (const [key, filePath] of Object.entries({
94
+ memory: HERMES_PATHS.memory,
95
+ user: HERMES_PATHS.user
96
+ })) {
97
+ if (fs.existsSync(filePath)) {
98
+ scan.memories.push({ type: key, path: filePath });
99
+ }
100
+ }
101
+
102
+ if (fs.existsSync(HERMES_PATHS.env)) {
103
+ const envMap = parseEnv(fs.readFileSync(HERMES_PATHS.env, 'utf8'));
104
+ for (const [key, value] of envMap.entries()) {
105
+ if (API_KEY_NAMES.includes(key) && value) {
106
+ scan.apiKeys[key] = value;
107
+ }
108
+ }
109
+ }
110
+
111
+ return scan;
112
+ }
113
+
114
+ function copyFileIfExists(src, dest) {
115
+ if (!fs.existsSync(src)) return false;
116
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
117
+ fs.copyFileSync(src, dest);
118
+ return true;
119
+ }
120
+
121
+ function copyDirContents(src, dest, extensions = ['.md']) {
122
+ if (!fs.existsSync(src)) return [];
123
+ const copied = [];
124
+ const files = fs.readdirSync(src);
125
+ for (const file of files) {
126
+ if (extensions && !extensions.some(ext => file.endsWith(ext))) continue;
127
+ const srcPath = path.join(src, file);
128
+ const destPath = path.join(dest, file);
129
+ fs.mkdirSync(dest, { recursive: true });
130
+ fs.copyFileSync(srcPath, destPath);
131
+ copied.push(file);
132
+ }
133
+ return copied;
134
+ }
135
+
136
+ async function ask(question, defaultValue = '') {
137
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
138
+ return new Promise((resolve) => {
139
+ const suffix = defaultValue ? ` [${defaultValue}]` : '';
140
+ rl.question(` ? ${question}${suffix}: `, (answer) => {
141
+ rl.close();
142
+ resolve(answer.trim() || defaultValue);
143
+ });
144
+ });
145
+ }
146
+
147
+ async function askChoice(question, options) {
148
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
149
+ return new Promise((resolve) => {
150
+ console.log(` ? ${question}`);
151
+ options.forEach((opt, i) => console.log(` [${i + 1}] ${opt}`));
152
+ rl.question(' Choice: ', (answer) => {
153
+ rl.close();
154
+ const idx = parseInt(answer, 10) - 1;
155
+ if (idx >= 0 && idx < options.length) {
156
+ resolve(options[idx]);
157
+ } else {
158
+ resolve(options[0]);
159
+ }
160
+ });
161
+ });
162
+ }
163
+
164
+ async function askOverwriteKey(key, existingSource, newSource) {
165
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
166
+ return new Promise((resolve) => {
167
+ console.log(` ⚠️ Conflict: ${key}`);
168
+ console.log(` Existing in: ${existingSource}`);
169
+ console.log(` Incoming from: ${newSource}`);
170
+ console.log(' [1] Keep existing');
171
+ console.log(' [2] Overwrite with new');
172
+ console.log(' [3] Skip this key');
173
+ rl.question(' Choice [1]: ', (answer) => {
174
+ rl.close();
175
+ const choice = answer.trim() || '1';
176
+ if (choice === '2') resolve('overwrite');
177
+ else if (choice === '3') resolve('skip');
178
+ else resolve('keep');
179
+ });
180
+ });
181
+ }
182
+
183
+ async function migrateOpenClaw(scan, options = {}) {
184
+ const { dryRun = false, conflictStrategy = 'ask' } = options;
185
+ const results = { skills: [], memories: [], apiKeys: {}, connections: [], errors: [] };
186
+
187
+ const skillsDest = path.join(NEOAGENT_SKILLS_DIR, 'openclaw-imports');
188
+ if (!dryRun) fs.mkdirSync(skillsDest, { recursive: true });
189
+ results.skills = copyDirContents(OPENCLAW_PATHS.skills, skillsDest, ['.md']);
190
+ if (results.skills.length > 0) {
191
+ console.log(` → Copied ${results.skills.length} skills to openclaw-imports/`);
192
+ }
193
+
194
+ const memoryDest = path.join(NEOAGENT_MEMORY_DIR, 'openclaw');
195
+ if (!dryRun) fs.mkdirSync(memoryDest, { recursive: true });
196
+ for (const mem of scan.memories) {
197
+ const destPath = path.join(memoryDest, path.basename(mem.path));
198
+ if (!dryRun) {
199
+ copyFileIfExists(mem.path, destPath);
200
+ }
201
+ results.memories.push(mem.type);
202
+ }
203
+ if (results.memories.length > 0) {
204
+ console.log(` → Copied ${results.memories.length} memory files`);
205
+ }
206
+
207
+ return results;
208
+ }
209
+
210
+ async function migrateHermes(scan, options = {}) {
211
+ const { dryRun = false } = options;
212
+ const results = { skills: [], memories: [], apiKeys: {}, connections: [], errors: [] };
213
+
214
+ const skillsDest = path.join(NEOAGENT_SKILLS_DIR, 'hermes-imports');
215
+ if (!dryRun) fs.mkdirSync(skillsDest, { recursive: true });
216
+ results.skills = copyDirContents(HERMES_PATHS.skills, skillsDest, ['.md']);
217
+ if (results.skills.length > 0) {
218
+ console.log(` → Copied ${results.skills.length} skills to hermes-imports/`);
219
+ }
220
+
221
+ const memoryDest = path.join(NEOAGENT_MEMORY_DIR, 'hermes');
222
+ if (!dryRun) fs.mkdirSync(memoryDest, { recursive: true });
223
+ for (const mem of scan.memories) {
224
+ const destPath = path.join(memoryDest, path.basename(mem.path));
225
+ if (!dryRun) {
226
+ copyFileIfExists(mem.path, destPath);
227
+ }
228
+ results.memories.push(mem.type);
229
+ }
230
+ if (results.memories.length > 0) {
231
+ console.log(` → Copied ${results.memories.length} memory files`);
232
+ }
233
+
234
+ return results;
235
+ }
236
+
237
+ async function mergeApiKeys(sources, options = {}) {
238
+ const { conflictStrategy = 'ask' } = options;
239
+ const results = {};
240
+ const conflicts = [];
241
+ const currentEnv = fs.existsSync(ENV_FILE)
242
+ ? parseEnv(fs.readFileSync(ENV_FILE, 'utf8'))
243
+ : new Map();
244
+
245
+ for (const [source, apiKeys] of Object.entries(sources)) {
246
+ for (const [key, value] of Object.entries(apiKeys)) {
247
+ if (!value) continue;
248
+ const existingValue = currentEnv.get ? currentEnv.get(key) : currentEnv[key];
249
+ if (existingValue && existingValue !== value) {
250
+ conflicts.push({ key, existingValue, newValue: value, source });
251
+ } else {
252
+ results[key] = value;
253
+ }
254
+ }
255
+ }
256
+
257
+ for (const conflict of conflicts) {
258
+ let resolution;
259
+ if (conflictStrategy === 'overwrite') {
260
+ resolution = 'overwrite';
261
+ } else if (conflictStrategy === 'skip') {
262
+ resolution = 'skip';
263
+ } else {
264
+ resolution = await askOverwriteKey(conflict.key, 'neoagent', conflict.source);
265
+ }
266
+
267
+ if (resolution === 'overwrite') {
268
+ results[conflict.key] = conflict.newValue;
269
+ } else if (resolution === 'skip') {
270
+ // keep existing, do nothing
271
+ } else {
272
+ results[conflict.key] = conflict.existingValue;
273
+ }
274
+ }
275
+
276
+ return results;
277
+ }
278
+
279
+ function writeMergedApiKeys(apiKeysToWrite) {
280
+ if (Object.keys(apiKeysToWrite).length === 0) return;
281
+
282
+ const currentLines = fs.existsSync(ENV_FILE)
283
+ ? fs.readFileSync(ENV_FILE, 'utf8').split('\n')
284
+ : [];
285
+
286
+ const existingKeys = new Set();
287
+ const newLines = [];
288
+
289
+ for (const line of currentLines) {
290
+ const match = line.match(/^([A-Z_]+)=/);
291
+ if (match && API_KEY_NAMES.includes(match[1])) {
292
+ if (apiKeysToWrite[match[1]] !== undefined) {
293
+ newLines.push(`${match[1]}=${apiKeysToWrite[match[1]]}`);
294
+ existingKeys.add(match[1]);
295
+ delete apiKeysToWrite[match[1]];
296
+ } else {
297
+ newLines.push(line);
298
+ }
299
+ } else {
300
+ newLines.push(line);
301
+ }
302
+ }
303
+
304
+ for (const [key, value] of Object.entries(apiKeysToWrite)) {
305
+ if (value) {
306
+ newLines.push(`${key}=${value}`);
307
+ }
308
+ }
309
+
310
+ fs.writeFileSync(ENV_FILE, newLines.join('\n') + '\n', { mode: 0o600 });
311
+ }
312
+
313
+ async function cmdMigrateDryRun(sources) {
314
+ console.log('\n=== Migration Dry Run ===\n');
315
+
316
+ if (sources.openclaw) {
317
+ console.log('OpenClaw detection: FOUND');
318
+ const scan = scanOpenClaw();
319
+ console.log(` Skills: ${scan.skills.length}`);
320
+ console.log(` Memories: ${scan.memories.length}`);
321
+ console.log(` API keys: ${Object.keys(scan.apiKeys).join(', ') || 'none'}`);
322
+ console.log(` Config: ${OPENCLAW_PATHS.config}`);
323
+ } else {
324
+ console.log('OpenClaw detection: NOT FOUND');
325
+ }
326
+
327
+ console.log();
328
+
329
+ if (sources.hermes) {
330
+ console.log('Hermes detection: FOUND');
331
+ const scan = scanHermes();
332
+ console.log(` Skills: ${scan.skills.length}`);
333
+ console.log(` Memories: ${scan.memories.length}`);
334
+ console.log(` API keys: ${Object.keys(scan.apiKeys).join(', ') || 'none'}`);
335
+ console.log(` Config: ${HERMES_PATHS.config}`);
336
+ } else {
337
+ console.log('Hermes detection: NOT FOUND');
338
+ }
339
+
340
+ console.log('\nWould migrate to:');
341
+ console.log(` Skills → ${NEOAGENT_SKILLS_DIR}`);
342
+ console.log(` Memories → ${NEOAGENT_MEMORY_DIR}`);
343
+ console.log(` API keys → ${ENV_FILE}`);
344
+ }
345
+
346
+ async function cmdMigrateRun(sources, options = {}) {
347
+ const { apiKeyStrategy = 'ask' } = options;
348
+
349
+ console.log('\n=== NeoAgent Migration ===\n');
350
+
351
+ const openclawScan = sources.openclaw ? scanOpenClaw() : null;
352
+ const hermesScan = sources.hermes ? scanHermes() : null;
353
+
354
+ console.log('Scanning sources...');
355
+ if (openclawScan) console.log(` OpenClaw: ${openclawScan.skills.length} skills, ${openclawScan.memories.length} memories, ${Object.keys(openclawScan.apiKeys).length} API keys`);
356
+ if (hermesScan) console.log(` Hermes: ${hermesScan.skills.length} skills, ${hermesScan.memories.length} memories, ${Object.keys(hermesScan.apiKeys).length} API keys`);
357
+
358
+ const allApiKeys = {};
359
+ if (openclawScan) Object.assign(allApiKeys, openclawScan.apiKeys);
360
+ if (hermesScan) Object.assign(allApiKeys, hermesScan.apiKeys);
361
+
362
+ console.log('\nMigrating skills and memories...');
363
+ const migratePromises = [];
364
+ if (sources.openclaw && openclawScan) {
365
+ migratePromises.push(migrateOpenClaw(openclawScan, options));
366
+ }
367
+ if (sources.hermes && hermesScan) {
368
+ migratePromises.push(migrateHermes(hermesScan, options));
369
+ }
370
+
371
+ const results = await Promise.all(migratePromises);
372
+
373
+ if (Object.keys(allApiKeys).length > 0) {
374
+ console.log('\nMerging API keys...');
375
+ const merged = await mergeApiKeys(
376
+ { openclaw: openclawScan?.apiKeys || {}, hermes: hermesScan?.apiKeys || {} },
377
+ { conflictStrategy: apiKeyStrategy }
378
+ );
379
+ writeMergedApiKeys(merged);
380
+ const addedCount = Object.keys(merged).filter(k => allApiKeys[k]).length;
381
+ console.log(` → Merged ${addedCount} API keys`);
382
+ }
383
+
384
+ console.log('\n=== Migration Complete ===\n');
385
+ console.log('Skills migrated to:');
386
+ if (sources.openclaw) console.log(` openclaw-imports/`);
387
+ if (sources.hermes) console.log(` hermes-imports/`);
388
+ console.log('\nMemories migrated to:');
389
+ if (sources.openclaw) console.log(` memory/openclaw/`);
390
+ if (sources.hermes) console.log(` memory/hermes/`);
391
+ console.log('\nRun `neoagent status` to verify the installation.');
392
+ console.log('Run `neoagent start` to start the server.\n');
393
+ }
394
+
395
+ module.exports = {
396
+ detectSourceAgents,
397
+ scanOpenClaw,
398
+ scanHermes,
399
+ migrateOpenClaw,
400
+ migrateHermes,
401
+ mergeApiKeys,
402
+ writeMergedApiKeys,
403
+ cmdMigrateDryRun,
404
+ cmdMigrateRun,
405
+ NEOAGENT_SKILLS_DIR,
406
+ NEOAGENT_MEMORY_DIR,
407
+ OPENCLAW_PATHS,
408
+ HERMES_PATHS
409
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neoagent",
3
- "version": "2.2.1-beta.7",
3
+ "version": "2.3.0",
4
4
  "description": "Proactive personal AI agent with no limits",
5
5
  "license": "MIT",
6
6
  "main": "server/index.js",
@@ -0,0 +1,173 @@
1
+ ---
2
+ name: agent-migration
3
+ description: Guides users through migrating from OpenClaw or Hermes to NeoAgent. Run this skill when a user wants to migrate their existing agent setup. Provides step-by-step guidance, dry-run previews, and handles API key conflicts interactively.
4
+ version: 1.0.0
5
+ metadata:
6
+ neoagent:
7
+ tags: [migration, openclaw, hermes, setup, import]
8
+ related_skills: []
9
+ ---
10
+
11
+ # Agent Migration Guide
12
+
13
+ Guides users through migrating their existing OpenClaw or Hermes agent setup to NeoAgent.
14
+
15
+ ## When to Use This Skill
16
+
17
+ Use this skill when:
18
+ - A user says they're migrating from OpenClaw or Hermes
19
+ - A user wants to import their existing skills, memories, or API keys
20
+ - A user runs `neoagent migrate` and needs guidance
21
+
22
+ ## How Migration Works
23
+
24
+ NeoAgent's migration system automatically detects existing OpenClaw (`~/.openclaw/`) and Hermes (`~/.hermes/`) installations and migrates:
25
+
26
+ | Data | Source | Destination |
27
+ |------|--------|-------------|
28
+ | **Skills** | `skills/*.md` in source | `~/.neoagent/agent-data/skills/[source]-imports/` |
29
+ | **Memories** | `SOUL.md`, `MEMORY.md`, `USER.md` | `~/.neoagent/agent-data/memory/[source]/` |
30
+ | **API Keys** | `.env` files | `~/.neoagent/.env` (merged with conflict prompts) |
31
+
32
+ ## Step-by-Step Migration Flow
33
+
34
+ ### Step 1: Check Migration Status
35
+
36
+ Ask the user to run:
37
+ ```
38
+ neoagent migrate status
39
+ ```
40
+
41
+ This will show which source agents are detected.
42
+
43
+ ### Step 2: Preview (Optional - Dry Run)
44
+
45
+ Ask the user to run:
46
+ ```
47
+ neoagent migrate dry-run
48
+ ```
49
+
50
+ This shows exactly what would be migrated without making any changes.
51
+
52
+ ### Step 3: Run Full Migration
53
+
54
+ Ask the user to run:
55
+ ```
56
+ neoagent migrate
57
+ ```
58
+
59
+ The migration will:
60
+ 1. Scan both sources (if present)
61
+ 2. Copy skills to import directories
62
+ 3. Copy memory files
63
+ 4. Merge API keys with interactive conflict resolution
64
+
65
+ ### Step 4: Verify Migration
66
+
67
+ After migration completes, advise the user to:
68
+ ```
69
+ neoagent status # Check server is running
70
+ neoagent start # Start the server if not running
71
+ ```
72
+
73
+ Imported skills appear in:
74
+ - `~/.neoagent/agent-data/skills/openclaw-imports/`
75
+ - `~/.neoagent/agent-data/skills/hermes-imports/`
76
+
77
+ Imported memories appear in:
78
+ - `~/.neoagent/agent-data/memory/openclaw/`
79
+ - `~/.neoagent/agent-data/memory/hermes/`
80
+
81
+ ## API Key Conflict Resolution
82
+
83
+ During migration, if an API key exists in multiple sources (including an existing NeoAgent config), the user will be prompted:
84
+
85
+ ```
86
+ ⚠️ Conflict: OPENAI_API_KEY
87
+ Existing in: neoagent
88
+ Incoming from: openclaw
89
+ [1] Keep existing (neoagent)
90
+ [2] Overwrite with new (openclaw)
91
+ [3] Skip this key
92
+ ```
93
+
94
+ Guide the user to choose based on their needs:
95
+ - **Keep existing**: If they want to preserve the current NeoAgent configuration
96
+ - **Overwrite**: If the incoming key is the one they want to use
97
+ - **Skip**: If they want to deal with it manually later
98
+
99
+ ## Troubleshooting
100
+
101
+ ### "No OpenClaw or Hermes installation detected"
102
+
103
+ **Cause**: The source directories don't exist at default locations.
104
+
105
+ **Solution**:
106
+ 1. Check if the installation is at a custom path
107
+ 2. Manually copy data:
108
+ - Skills: Copy `*.md` files to `~/.neoagent/agent-data/skills/`
109
+ - Memories: Copy to `~/.neoagent/agent-data/memory/`
110
+ - API keys: Edit `~/.neoagent/.env` manually
111
+
112
+ ### "Permission denied" errors
113
+
114
+ **Cause**: Missing read permissions on source or write permissions on target.
115
+
116
+ **Solution**: Ensure the user has appropriate permissions:
117
+ ```bash
118
+ chmod 755 ~/.openclaw
119
+ chmod 755 ~/.hermes
120
+ chmod 755 ~/.neoagent
121
+ ```
122
+
123
+ ### Migration seems incomplete
124
+
125
+ **Cause**: Some files may have already existed and were skipped (migration is idempotent).
126
+
127
+ **Solution**: Re-run migration - it won't overwrite existing files.
128
+
129
+ ## Manual Migration (If Automated Fails)
130
+
131
+ If the automated migration doesn't work:
132
+
133
+ ### For Skills
134
+ ```bash
135
+ # Create import directory
136
+ mkdir -p ~/.neoagent/agent-data/skills/openclaw-imports
137
+
138
+ # Copy all .md files
139
+ cp ~/.openclaw/skills/*.md ~/.neoagent/agent-data/skills/openclaw-imports/
140
+ ```
141
+
142
+ ### For Memories
143
+ ```bash
144
+ # Create source directory
145
+ mkdir -p ~/.neoagent/agent-data/memory/openclaw
146
+
147
+ # Copy memory files
148
+ cp ~/.openclaw/workspace/SOUL.md ~/.neoagent/agent-data/memory/openclaw/
149
+ cp ~/.openclaw/workspace/MEMORY.md ~/.neoagent/agent-data/memory/openclaw/
150
+ cp ~/.openclaw/workspace/USER.md ~/.neoagent/agent-data/memory/openclaw/
151
+ ```
152
+
153
+ ### For API Keys
154
+ ```bash
155
+ # Edit the .env file
156
+ nano ~/.neoagent/.env
157
+
158
+ # Add keys from source, e.g.:
159
+ # OPENAI_API_KEY=sk-...
160
+ # ANTHROPIC_API_KEY=sk-ant-...
161
+ ```
162
+
163
+ ## Post-Migration Checklist
164
+
165
+ After successful migration, advise the user to:
166
+
167
+ - [ ] Run `neoagent status` to verify server is healthy
168
+ - [ ] Run `neoagent start` if server isn't running
169
+ - [ ] Review imported skills in `~/.neoagent/agent-data/skills/`
170
+ - [ ] Review imported memories in `~/.neoagent/agent-data/memory/`
171
+ - [ ] Verify API keys are correctly set with `neoagent env list`
172
+ - [ ] Test the agent by sending a message in the UI
173
+ - [ ] Check logs if anything seems wrong: `neoagent logs`
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"59aa584fdf100e6c78c785d8a5b565d1de4b48
37
37
 
38
38
  _flutter.loader.load({
39
39
  serviceWorkerSettings: {
40
- serviceWorkerVersion: "3421203079" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
40
+ serviceWorkerVersion: "282358507" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
41
41
  }
42
42
  });