natureco-cli 2.13.17 → 2.13.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "2.13.17",
3
+ "version": "2.13.19",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "main": "bin/natureco.js",
6
6
  "bin": {
@@ -211,7 +211,7 @@ body::before{
211
211
  <div class="header-bot-name" id="header-bot-name">Nature Bot</div>
212
212
  <div class="header-bot-model" id="header-bot-model">NatureCo</div>
213
213
  </div>
214
- <div class="version-badge" id="version-badge">v2.13.17</div>
214
+ <div class="version-badge" id="version-badge">v2.13.19</div>
215
215
  </div>
216
216
  <div class="messages" id="messages"></div>
217
217
  <div class="input-area">
@@ -341,7 +341,7 @@ function dashboard(action) {
341
341
  apiKey: cfg.apiKey,
342
342
  defaultBot: cfg.defaultBot,
343
343
  defaultBotId: cfg.defaultBotId,
344
- version: 'v2.13.17',
344
+ version: 'v2.13.19',
345
345
  bots: cfg.bots || [],
346
346
  telegramToken: cfg.telegramToken || null,
347
347
  whatsappConnected: cfg.whatsappConnected || false,
@@ -74,11 +74,12 @@ async function migrate(options) {
74
74
  const nameMatch = userMd.match(/Name:\s*(.+)/i);
75
75
  const timezoneMatch = userMd.match(/Timezone:\s*(.+)/i);
76
76
  const notesMatch = userMd.match(/Notes:\s*(.+)/i);
77
- const botNameMatch = userMd.match(/What to call them:\s*\*\*(.+?)\*\*/i);
77
+ const nicknameMatch = userMd.match(/What to call them:\s*\*\*(.+?)\*\*/i);
78
78
 
79
79
  const memory = {
80
80
  name: nameMatch ? nameMatch[1].trim() : null,
81
- botName: botNameMatch ? botNameMatch[1].trim() : null,
81
+ nickname: nicknameMatch ? nicknameMatch[1].trim() : null,
82
+ botName: null, // Will be extracted from agents directory or MEMORY.md
82
83
  facts: []
83
84
  };
84
85
 
@@ -87,8 +88,28 @@ async function migrate(options) {
87
88
  memory.name = memory.name.replace(/\*\*/g, '').trim();
88
89
  }
89
90
 
90
- if (memory.botName) {
91
- memory.botName = memory.botName.replace(/\*\*/g, '').trim();
91
+ if (memory.nickname) {
92
+ memory.nickname = memory.nickname.replace(/\*\*/g, '').trim();
93
+ }
94
+
95
+ // Extract botName from agents directory (primary method)
96
+ // ~/.openclaw/agents/ichigo/ → botName = "İchigo"
97
+ const agentsDir = path.join(openclawDir, 'agents');
98
+ if (fs.existsSync(agentsDir)) {
99
+ try {
100
+ const agents = fs.readdirSync(agentsDir).filter(a => {
101
+ const agentPath = path.join(agentsDir, a);
102
+ return a !== 'main' && !a.startsWith('.') && fs.statSync(agentPath).isDirectory();
103
+ });
104
+
105
+ if (agents.length > 0) {
106
+ // Capitalize first letter: ichigo → İchigo
107
+ const agentName = agents[0];
108
+ memory.botName = agentName.charAt(0).toUpperCase() + agentName.slice(1);
109
+ }
110
+ } catch (err) {
111
+ // Silently fail if agents directory can't be read
112
+ }
92
113
  }
93
114
 
94
115
  if (timezoneMatch) {
@@ -143,6 +164,25 @@ async function migrate(options) {
143
164
  try {
144
165
  const content = fs.readFileSync(file, 'utf8');
145
166
 
167
+ // Extract bot name from MEMORY.md (first file only)
168
+ if (!memory.botName && file === mainMemoryPath) {
169
+ // Try multiple patterns for bot name
170
+ const botNamePatterns = [
171
+ /[İI]sim:\s*([^\n]+)/, // İsim: İchigo
172
+ /Ben[,\s]+([A-ZÇĞİÖŞÜ][a-zçğıöşü]+)/, // Ben, İchigo
173
+ /Adım[,\s]+([A-ZÇĞİÖŞÜ][a-zçğıöşü]+)/, // Adım İchigo
174
+ /Ben\s+([A-ZÇĞİÖŞÜ][a-zçğıöşü]+)['']?[ıi]m/ // Ben İchigo'yum
175
+ ];
176
+
177
+ for (const pattern of botNamePatterns) {
178
+ const match = content.match(pattern);
179
+ if (match) {
180
+ memory.botName = match[1].trim().replace(/\*\*/g, '').trim();
181
+ break;
182
+ }
183
+ }
184
+ }
185
+
146
186
  // Extract meaningful lines (skip headers, empty lines, useless patterns)
147
187
  const lines = content.split('\n')
148
188
  .filter(l => l.trim() && !l.startsWith('#'))
@@ -164,6 +204,29 @@ async function migrate(options) {
164
204
  }
165
205
  }
166
206
 
207
+ // Fallback: Extract botName from cron job names if still not found
208
+ // "Ichigo Brain — ..." → Ichigo
209
+ if (!memory.botName) {
210
+ try {
211
+ const cronJobsPath = path.join(openclawDir, 'cron', 'jobs.json');
212
+
213
+ if (fs.existsSync(cronJobsPath)) {
214
+ const cronData = JSON.parse(fs.readFileSync(cronJobsPath, 'utf8'));
215
+ const jobs = cronData.jobs || cronData || [];
216
+
217
+ for (const job of jobs) {
218
+ const nameMatch = job.name?.match(/^([A-ZÇĞİÖŞÜa-zçğıöşü]+)\s+(Brain|Briefing|Report)/i);
219
+ if (nameMatch && nameMatch[1].toLowerCase() !== 'natureco') {
220
+ memory.botName = nameMatch[1];
221
+ break;
222
+ }
223
+ }
224
+ }
225
+ } catch (err) {
226
+ // Silently fail
227
+ }
228
+ }
229
+
167
230
  // Save to NatureCo memory
168
231
  const memoryDir = path.join(os.homedir(), '.natureco', 'memory');
169
232
  fs.mkdirSync(memoryDir, { recursive: true });
@@ -24,6 +24,7 @@ function loadMemory(botId) {
24
24
  if (!fs.existsSync(filePath)) {
25
25
  return {
26
26
  name: '',
27
+ nickname: '',
27
28
  botName: '',
28
29
  preferences: [],
29
30
  facts: [],
@@ -38,6 +39,7 @@ function loadMemory(botId) {
38
39
  // Return with safe defaults for all fields
39
40
  const memory = {
40
41
  name: data.name || '',
42
+ nickname: data.nickname || '',
41
43
  botName: data.botName || '',
42
44
  preferences: data.preferences || [],
43
45
  facts: data.facts || [],
@@ -56,6 +58,7 @@ function loadMemory(botId) {
56
58
  } catch {
57
59
  return {
58
60
  name: '',
61
+ nickname: '',
59
62
  botName: '',
60
63
  preferences: [],
61
64
  facts: [],
@@ -83,6 +86,8 @@ function addMemoryEntry(botId, key, value) {
83
86
 
84
87
  if (key === 'name') {
85
88
  memory.name = value;
89
+ } else if (key === 'nickname') {
90
+ memory.nickname = value;
86
91
  } else if (key === 'botName') {
87
92
  memory.botName = value;
88
93
  } else if (key === 'preference') {
@@ -202,6 +207,7 @@ function getMemoryPrompt(botId) {
202
207
 
203
208
  // Safe defaults for all fields
204
209
  const name = memory.name || '';
210
+ const nickname = memory.nickname || '';
205
211
  const botName = memory.botName || '';
206
212
  const preferences = memory.preferences || [];
207
213
  const facts = memory.facts || [];
@@ -214,18 +220,22 @@ function getMemoryPrompt(botId) {
214
220
  }
215
221
 
216
222
  // Check if there's any content to add
217
- if (!name && !botName && preferences.length === 0 && facts.length === 0) {
223
+ if (!name && !nickname && !botName && preferences.length === 0 && facts.length === 0) {
218
224
  return '';
219
225
  }
220
226
 
221
227
  // Add user memory section
222
- if (name || preferences.length > 0 || facts.length > 0) {
228
+ if (name || nickname || preferences.length > 0 || facts.length > 0) {
223
229
  parts.push('## Kullanıcı Hafızası');
224
230
 
225
231
  if (name) {
226
232
  parts.push(`İsim: ${name}`);
227
233
  }
228
234
 
235
+ if (nickname) {
236
+ parts.push(`Lakap: ${nickname}`);
237
+ }
238
+
229
239
  if (preferences.length > 0) {
230
240
  const sorted = preferences.sort((a, b) => b.score - a.score);
231
241
  parts.push(`Tercihler: ${sorted.map(p => p.value).join(', ')}`);