natureco-cli 1.0.1 → 1.0.5

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/bin/natureco.js CHANGED
@@ -47,7 +47,10 @@ program
47
47
  program
48
48
  .command('chat <bot-name>')
49
49
  .description('Start interactive chat with a bot')
50
- .action(chat);
50
+ .option('--resume [session-id]', 'Resume a previous session')
51
+ .action((botName, options) => {
52
+ chat(botName, options);
53
+ });
51
54
 
52
55
  program
53
56
  .command('init')
@@ -93,6 +96,54 @@ program
93
96
  updateCmd();
94
97
  });
95
98
 
99
+ program
100
+ .command('commands [action] [params...]')
101
+ .description('Manage custom commands (list|create)')
102
+ .action((action, params) => {
103
+ const commandsCmd = require('../src/commands/commands');
104
+ commandsCmd(action, ...(params || []));
105
+ });
106
+
107
+ program
108
+ .command('cron [action] [params...]')
109
+ .description('Manage cron jobs (list|add|remove|run|enable|disable|start|logs)')
110
+ .action((action, params) => {
111
+ const cronCmd = require('../src/commands/cron');
112
+ cronCmd(action, ...(params || []));
113
+ });
114
+
115
+ program
116
+ .command('hooks [action] [params...]')
117
+ .description('Manage hooks (list|create)')
118
+ .action((action, params) => {
119
+ const hooksCmd = require('../src/commands/hooks');
120
+ hooksCmd(action, ...(params || []));
121
+ });
122
+
123
+ program
124
+ .command('sessions [action] [params...]')
125
+ .description('Manage chat sessions (list|show)')
126
+ .action((action, params) => {
127
+ const sessionsCmd = require('../src/commands/sessions');
128
+ sessionsCmd(action, ...(params || []));
129
+ });
130
+
131
+ program
132
+ .command('git <action>')
133
+ .description('Git integration (review|commit|pr|explain)')
134
+ .action((action) => {
135
+ const gitCmd = require('../src/commands/git');
136
+ gitCmd(action);
137
+ });
138
+
139
+ program
140
+ .command('tasks [action] [params...]')
141
+ .description('Manage background tasks (list|show)')
142
+ .action((action, params) => {
143
+ const tasksCmd = require('../src/commands/tasks');
144
+ tasksCmd(action, ...(params || []));
145
+ });
146
+
96
147
  program
97
148
  .command('help')
98
149
  .description('Show help information')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.5",
4
4
  "description": "NatureCo AI Bot Terminal Interface",
5
5
  "main": "bin/natureco.js",
6
6
  "bin": {
@@ -24,13 +24,13 @@
24
24
  "author": "NatureCo",
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
+ "boxen": "^5.1.2",
27
28
  "chalk": "^4.1.2",
28
29
  "commander": "^11.1.0",
29
- "inquirer": "^8.2.7",
30
- "boxen": "^5.1.2",
31
- "ora": "^5.4.1",
32
30
  "conf": "^10.2.0",
33
- "update-notifier": "^6.0.2"
31
+ "inquirer": "^8.2.7",
32
+ "node-cron": "^2.0.3",
33
+ "ora": "^5.4.1"
34
34
  },
35
35
  "engines": {
36
36
  "node": ">=16.0.0"
@@ -6,8 +6,13 @@ const { getBots, sendMessage } = require('../utils/api');
6
6
  const { getSkillPrompts, getSkills } = require('../utils/skills');
7
7
  const { getAgentsPrompt } = require('../utils/agents');
8
8
  const { addToHistory, getCommandHistory, clearHistory } = require('../utils/history');
9
+ const { getMemoryPrompt, extractMemoryFromMessage, loadMemory, clearMemory } = require('../utils/memory');
10
+ const { getCommands, getCommandContent } = require('../utils/commands');
11
+ const { runHooks } = require('../utils/hooks');
12
+ const { createSession, loadSession, getLatestSession, addMessageToSession } = require('../utils/sessions');
13
+ const { addBackgroundTask, updateBackgroundTask } = require('../utils/background');
9
14
 
10
- async function chat(botName) {
15
+ async function chat(botName, options = {}) {
11
16
  const apiKey = getApiKey();
12
17
 
13
18
  if (!apiKey) {
@@ -46,11 +51,57 @@ async function chat(botName) {
46
51
  console.log(chalk.green.bold(`╭─ NatureCo Terminal ─╮`));
47
52
  console.log(chalk.green(`│ ${bot.name.padEnd(18)} │`));
48
53
  console.log(chalk.green(`╰─────────────────────╯\n`));
49
- console.log(chalk.gray('Chat komutları: /clear /bot /skills /help\n'));
54
+
55
+ // Session management
56
+ let session;
57
+ if (options.resume) {
58
+ if (options.resume === true) {
59
+ // Resume latest session
60
+ session = getLatestSession(bot.id);
61
+ if (session) {
62
+ console.log(chalk.blue(`📂 Resumed session: ${session.id}\n`));
63
+ // Display last few messages
64
+ const lastMessages = session.messages.slice(-3);
65
+ lastMessages.forEach(msg => {
66
+ console.log(chalk.cyan(`siz › ${msg.user}`));
67
+ console.log(chalk.green(`bot › ${msg.bot}\n`));
68
+ });
69
+ } else {
70
+ console.log(chalk.gray('No previous session found. Starting new session.\n'));
71
+ session = createSession(bot.id, bot.name);
72
+ }
73
+ } else {
74
+ // Resume specific session
75
+ session = loadSession(bot.id, options.resume);
76
+ if (session) {
77
+ console.log(chalk.blue(`📂 Resumed session: ${session.id}\n`));
78
+ // Display last few messages
79
+ const lastMessages = session.messages.slice(-3);
80
+ lastMessages.forEach(msg => {
81
+ console.log(chalk.cyan(`siz › ${msg.user}`));
82
+ console.log(chalk.green(`bot › ${msg.bot}\n`));
83
+ });
84
+ } else {
85
+ console.log(chalk.red(`❌ Session not found: ${options.resume}\n`));
86
+ process.exit(1);
87
+ }
88
+ }
89
+ } else {
90
+ // Create new session
91
+ session = createSession(bot.id, bot.name);
92
+ console.log(chalk.gray(`Session ID: ${session.id} · Resume with: --resume ${session.id}\n`));
93
+ }
94
+
95
+ console.log(chalk.gray('Chat komutları: /clear /bot /skills /memory /commands /help\n'));
96
+ console.log(chalk.gray('Ctrl+B: Arka plana al | Ctrl+C: Çık\n'));
97
+
98
+ // Run on-start hooks
99
+ await runHooks('on-start', null, { botId: bot.id, botName: bot.name });
50
100
 
51
- // Skill prompts ve AGENTS.md'yi yükle
101
+ // Skill prompts, AGENTS.md ve hafızayı yükle
52
102
  const skillPrompts = getSkillPrompts();
53
103
  const agentsPrompt = getAgentsPrompt();
104
+ const memoryPrompt = getMemoryPrompt(bot.id);
54
105
 
55
106
  // Sistem promptunu birleştir
56
107
  let systemPrompt = '';
@@ -59,6 +110,10 @@ async function chat(botName) {
59
110
  if (systemPrompt) systemPrompt += '\n\n';
60
111
  systemPrompt += `## Project Instructions\n${agentsPrompt}`;
61
112
  }
113
+ if (memoryPrompt) {
114
+ if (systemPrompt) systemPrompt += '\n\n';
115
+ systemPrompt += memoryPrompt;
116
+ }
62
117
 
63
118
  let conversationId = null;
64
119
 
@@ -76,9 +131,54 @@ async function chat(botName) {
76
131
 
77
132
  // Load command history
78
133
  commandHistory.forEach(cmd => rl.history.unshift(cmd));
134
+
135
+ // Ctrl+B handler for background tasks
136
+ let currentMessage = '';
137
+
138
+ process.stdin.on('keypress', (str, key) => {
139
+ if (key && key.ctrl && key.name === 'b') {
140
+ if (currentMessage && currentMessage.trim()) {
141
+ const task = addBackgroundTask({
142
+ botId: bot.id,
143
+ botName: bot.name,
144
+ message: currentMessage,
145
+ });
146
+ console.log(chalk.yellow(`\n📦 Task moved to background: ${task.id}`));
147
+ console.log(chalk.gray('View with: natureco tasks show ' + task.id + '\n'));
148
+
149
+ // Run task in background
150
+ sendMessage(apiKey, bot.id, currentMessage, conversationId, systemPrompt)
151
+ .then(response => {
152
+ const reply = response.reply || response.message || 'No response';
153
+ updateBackgroundTask(task.id, {
154
+ status: 'completed',
155
+ result: reply,
156
+ completedAt: new Date().toISOString(),
157
+ });
158
+ })
159
+ .catch(err => {
160
+ updateBackgroundTask(task.id, {
161
+ status: 'failed',
162
+ error: err.message,
163
+ completedAt: new Date().toISOString(),
164
+ });
165
+ });
166
+
167
+ currentMessage = '';
168
+ rl.prompt();
169
+ }
170
+ }
171
+ });
172
+
173
+ // Enable keypress events
174
+ if (process.stdin.isTTY) {
175
+ process.stdin.setRawMode(true);
176
+ }
177
+ readline.emitKeypressEvents(process.stdin);
79
178
 
80
179
  async function processMessage(userMessage) {
81
180
  userMessage = userMessage.trim();
181
+ currentMessage = userMessage;
82
182
 
83
183
  if (!userMessage || userMessage.length === 0) {
84
184
  rl.prompt();
@@ -95,7 +195,7 @@ async function chat(botName) {
95
195
  console.log(chalk.green.bold(`╭─ NatureCo Terminal ─╮`));
96
196
  console.log(chalk.green(`│ ${bot.name.padEnd(18)} │`));
97
197
  console.log(chalk.green(`╰─────────────────────╯\n`));
98
- console.log(chalk.gray('Chat komutları: /clear /bot /skills /help\n'));
198
+ console.log(chalk.gray('Chat komutları: /clear /bot /skills /commands /help\n'));
99
199
  rl.prompt();
100
200
  return;
101
201
 
@@ -124,7 +224,9 @@ async function chat(botName) {
124
224
 
125
225
  bot = newBot;
126
226
  conversationId = null;
227
+ session = createSession(bot.id, bot.name);
127
228
  console.log(chalk.green(`\n✅ Bot değiştirildi: ${bot.name}\n`));
229
+ console.log(chalk.gray(`Session ID: ${session.id}\n`));
128
230
  rl.prompt();
129
231
  return;
130
232
 
@@ -143,18 +245,99 @@ async function chat(botName) {
143
245
  rl.prompt();
144
246
  return;
145
247
 
248
+ case 'memory':
249
+ if (args.length > 0 && args[0] === 'clear') {
250
+ clearMemory(bot.id);
251
+ console.log(chalk.green('\n✅ Hafıza temizlendi\n'));
252
+ rl.prompt();
253
+ return;
254
+ }
255
+
256
+ const memory = loadMemory(bot.id);
257
+ console.log(chalk.yellow('\nHafıza:\n'));
258
+ if (memory.name) {
259
+ console.log(chalk.cyan(' İsim:'), chalk.white(memory.name));
260
+ }
261
+ if (memory.preferences.length > 0) {
262
+ console.log(chalk.cyan(' Tercihler:'), chalk.white(memory.preferences.join(', ')));
263
+ }
264
+ if (memory.facts.length > 0) {
265
+ console.log(chalk.cyan(' Bilgiler:'), chalk.white(memory.facts.join(', ')));
266
+ }
267
+ if (!memory.name && memory.preferences.length === 0 && memory.facts.length === 0) {
268
+ console.log(chalk.gray(' Henüz hafıza yok'));
269
+ }
270
+ console.log('');
271
+ rl.prompt();
272
+ return;
273
+
274
+ case 'commands':
275
+ const commands = getCommands();
276
+ if (commands.length === 0) {
277
+ console.log(chalk.gray('\nÖzel komut yok.\n'));
278
+ console.log(chalk.gray('Oluşturmak için: natureco commands create <ad>\n'));
279
+ } else {
280
+ console.log(chalk.yellow('\nÖzel Komutlar:\n'));
281
+ commands.forEach(cmd => {
282
+ const sourceLabel = cmd.source === 'user' ? chalk.blue('[global]') : chalk.green('[project]');
283
+ console.log(` ${sourceLabel} ${chalk.cyan('/' + cmd.name)}`);
284
+ });
285
+ console.log('');
286
+ }
287
+ rl.prompt();
288
+ return;
289
+
146
290
  case 'help':
147
291
  console.log(chalk.yellow('\nChat Komutları:\n'));
148
292
  console.log(chalk.cyan(' /clear') + chalk.gray(' - Ekranı temizle'));
149
293
  console.log(chalk.cyan(' /bot [ad]') + chalk.gray(' - Bot değiştir veya listele'));
150
294
  console.log(chalk.cyan(' /skills') + chalk.gray(' - Aktif skill\'leri göster'));
295
+ console.log(chalk.cyan(' /memory') + chalk.gray(' - Hafızayı göster'));
296
+ console.log(chalk.cyan(' /memory clear') + chalk.gray(' - Hafızayı temizle'));
297
+ console.log(chalk.cyan(' /commands') + chalk.gray(' - Özel komutları listele'));
151
298
  console.log(chalk.cyan(' /help') + chalk.gray(' - Bu yardım mesajını göster'));
152
299
  console.log(chalk.cyan(' exit, quit') + chalk.gray(' - Chat\'ten çık'));
153
- console.log(chalk.gray('\nYukarı/aşağı ok tuşları ile komut geçmişinde gezin.\n'));
300
+ console.log(chalk.gray('\nYukarı/aşağı ok tuşları ile komut geçmişinde gezin.'));
301
+ console.log(chalk.gray('Ctrl+B: Görevi arka plana al\n'));
154
302
  rl.prompt();
155
303
  return;
156
304
 
157
305
  default:
306
+ // Check for custom commands
307
+ const customCommand = getCommandContent(command);
308
+ if (customCommand) {
309
+ console.log(chalk.blue(`\n📝 Using custom command: /${command}\n`));
310
+ // Add custom command to system prompt
311
+ const customPrompt = systemPrompt + '\n\n## Custom Command\n' + customCommand;
312
+
313
+ // If there are args, use them as the message
314
+ const message = args.length > 0 ? args.join(' ') : 'Execute the custom command instruction';
315
+
316
+ const loadingInterval = startLoadingAnimation();
317
+
318
+ try {
319
+ const response = await sendMessage(apiKey, bot.id, message, conversationId, customPrompt);
320
+
321
+ stopLoadingAnimation(loadingInterval);
322
+
323
+ if (response.conversation_id) {
324
+ conversationId = response.conversation_id;
325
+ }
326
+
327
+ const botReply = response.reply || response.message || 'No response';
328
+ console.log(chalk.green(`bot › ${botReply}\n`));
329
+
330
+ addToHistory(bot.id, userMessage, botReply, conversationId);
331
+ addMessageToSession(bot.id, session.id, userMessage, botReply);
332
+ } catch (err) {
333
+ stopLoadingAnimation(loadingInterval);
334
+ console.log(chalk.red(`\n❌ Error: ${err.message}\n`));
335
+ }
336
+
337
+ rl.prompt();
338
+ return;
339
+ }
340
+
158
341
  console.log(chalk.red(`\n❌ Bilinmeyen komut: /${command}`));
159
342
  console.log(chalk.gray('Yardım için: /help\n'));
160
343
  rl.prompt();
@@ -164,11 +347,15 @@ async function chat(botName) {
164
347
 
165
348
  // Exit komutu
166
349
  if (userMessage.toLowerCase() === 'exit' || userMessage.toLowerCase() === 'quit') {
350
+ await runHooks('on-exit', null, { botId: bot.id, botName: bot.name });
167
351
  console.log(chalk.gray('\n👋 Goodbye!\n'));
168
352
  rl.close();
169
353
  process.exit(0);
170
354
  }
171
355
 
356
+ // Run pre-message hooks
357
+ userMessage = await runHooks('pre-message', userMessage, { botId: bot.id, botName: bot.name });
358
+
172
359
  // Loading animasyonu
173
360
  const loadingInterval = startLoadingAnimation();
174
361
 
@@ -181,16 +368,29 @@ async function chat(botName) {
181
368
  conversationId = response.conversation_id;
182
369
  }
183
370
 
184
- const botReply = response.reply || response.message || 'No response';
371
+ let botReply = response.reply || response.message || 'No response';
372
+
373
+ // Run post-message hooks
374
+ botReply = await runHooks('post-message', botReply, { botId: bot.id, botName: bot.name });
375
+
185
376
  console.log(chalk.green(`bot › ${botReply}\n`));
186
377
 
187
- // Save to history
378
+ // Save to history and session
188
379
  addToHistory(bot.id, userMessage, botReply, conversationId);
380
+ addMessageToSession(bot.id, session.id, userMessage, botReply);
381
+
382
+ // Extract and save memory
383
+ const memoryEntries = extractMemoryFromMessage(userMessage);
384
+ for (const entry of memoryEntries) {
385
+ const { addMemoryEntry } = require('../utils/memory');
386
+ addMemoryEntry(bot.id, entry.key, entry.value);
387
+ }
189
388
  } catch (err) {
190
389
  stopLoadingAnimation(loadingInterval);
191
390
  console.log(chalk.red(`\n❌ Error: ${err.message}\n`));
192
391
  }
193
392
 
393
+ currentMessage = '';
194
394
  rl.prompt();
195
395
  }
196
396
 
@@ -199,8 +399,10 @@ async function chat(botName) {
199
399
  });
200
400
 
201
401
  rl.on('close', () => {
202
- console.log(chalk.gray('\n👋 Goodbye!\n'));
203
- process.exit(0);
402
+ runHooks('on-exit', null, { botId: bot.id, botName: bot.name }).then(() => {
403
+ console.log(chalk.gray('\n👋 Goodbye!\n'));
404
+ process.exit(0);
405
+ });
204
406
  });
205
407
 
206
408
  rl.prompt();
@@ -0,0 +1,74 @@
1
+ const inquirer = require('inquirer');
2
+ const chalk = require('chalk');
3
+ const { getCommands, createCommand } = require('../utils/commands');
4
+
5
+ async function commands(action, ...args) {
6
+ if (!action || action === 'list') {
7
+ return listCommands();
8
+ }
9
+
10
+ if (action === 'create') {
11
+ const name = args[0];
12
+ if (!name) {
13
+ console.log(chalk.red('\n❌ Command name required\n'));
14
+ console.log(chalk.gray('Usage: natureco commands create <name>\n'));
15
+ process.exit(1);
16
+ }
17
+ return createCommandInteractive(name);
18
+ }
19
+
20
+ console.log(chalk.red(`\n❌ Unknown action: ${action}\n`));
21
+ console.log(chalk.gray('Available actions: list, create\n'));
22
+ process.exit(1);
23
+ }
24
+
25
+ function listCommands() {
26
+ const commands = getCommands();
27
+
28
+ if (commands.length === 0) {
29
+ console.log(chalk.gray('\nNo custom commands found.\n'));
30
+ console.log(chalk.gray('Create one with: natureco commands create <name>\n'));
31
+ return;
32
+ }
33
+
34
+ console.log(chalk.yellow('\nCustom Commands:\n'));
35
+
36
+ commands.forEach(cmd => {
37
+ const sourceLabel = cmd.source === 'user' ? chalk.blue('[global]') : chalk.green('[project]');
38
+ console.log(` ${sourceLabel} ${chalk.cyan('/' + cmd.name)}`);
39
+ const preview = cmd.content.split('\n').find(line => line.trim() && !line.startsWith('#'));
40
+ if (preview) {
41
+ console.log(chalk.gray(` ${preview.trim().slice(0, 60)}...`));
42
+ }
43
+ });
44
+
45
+ console.log('');
46
+ }
47
+
48
+ async function createCommandInteractive(name) {
49
+ process.stdin.resume();
50
+
51
+ const answers = await inquirer.prompt([
52
+ {
53
+ type: 'list',
54
+ name: 'scope',
55
+ message: 'Command scope:',
56
+ choices: [
57
+ { name: 'Project (only this project)', value: 'project' },
58
+ { name: 'Global (all projects)', value: 'user' },
59
+ ],
60
+ default: 'project',
61
+ },
62
+ ]);
63
+
64
+ try {
65
+ const filePath = createCommand(name, answers.scope);
66
+ console.log(chalk.green(`\n✅ Command created: ${filePath}\n`));
67
+ console.log(chalk.gray(`Edit the file and use it in chat with: /${name}\n`));
68
+ } catch (err) {
69
+ console.log(chalk.red(`\n❌ Error: ${err.message}\n`));
70
+ process.exit(1);
71
+ }
72
+ }
73
+
74
+ module.exports = commands;