natureco-cli 2.8.2 → 2.9.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/bin/natureco.js +4 -3
- package/package.json +2 -2
- package/src/commands/cron.js +128 -336
- package/src/commands/dashboard.js +2 -2
- package/src/commands/gateway-server.js +98 -3
package/bin/natureco.js
CHANGED
|
@@ -106,11 +106,12 @@ program
|
|
|
106
106
|
});
|
|
107
107
|
|
|
108
108
|
program
|
|
109
|
-
.command('cron
|
|
110
|
-
.description('Manage
|
|
109
|
+
.command('cron <action> [params...]')
|
|
110
|
+
.description('Manage scheduled tasks (add|list|remove)')
|
|
111
111
|
.action((action, params) => {
|
|
112
112
|
const cronCmd = require('../src/commands/cron');
|
|
113
|
-
|
|
113
|
+
const args = process.argv.slice(3); // Get all args after 'cron'
|
|
114
|
+
cronCmd(args);
|
|
114
115
|
});
|
|
115
116
|
|
|
116
117
|
program
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "NatureCo AI Bot Terminal Interface",
|
|
5
5
|
"main": "bin/natureco.js",
|
|
6
6
|
"bin": {
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"conf": "^10.2.0",
|
|
32
32
|
"eventsource": "^2.0.2",
|
|
33
33
|
"inquirer": "^8.2.7",
|
|
34
|
-
"node-cron": "^
|
|
34
|
+
"node-cron": "^3.0.3",
|
|
35
35
|
"node-telegram-bot-api": "^0.65.1",
|
|
36
36
|
"ora": "^5.4.1",
|
|
37
37
|
"pino": "^8.21.0",
|
package/src/commands/cron.js
CHANGED
|
@@ -1,383 +1,175 @@
|
|
|
1
|
-
const inquirer = require('inquirer');
|
|
2
1
|
const chalk = require('chalk');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const {
|
|
7
|
-
loadCronJobs,
|
|
8
|
-
addCronJob,
|
|
9
|
-
removeCronJob,
|
|
10
|
-
updateCronJob,
|
|
11
|
-
getCronJob,
|
|
12
|
-
parseCronSchedule,
|
|
13
|
-
validateCronExpression,
|
|
14
|
-
logCronOutput,
|
|
15
|
-
getCronLog,
|
|
16
|
-
} = require('../utils/cron');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const os = require('os');
|
|
17
5
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return addCronJobInteractive();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
if (action === 'remove') {
|
|
28
|
-
const id = args[0];
|
|
29
|
-
if (!id) {
|
|
30
|
-
console.log(chalk.red('\n❌ Job ID required\n'));
|
|
31
|
-
console.log(chalk.gray('Usage: natureco cron remove <id>\n'));
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
return removeCronJobCommand(id);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (action === 'run') {
|
|
38
|
-
const id = args[0];
|
|
39
|
-
if (!id) {
|
|
40
|
-
console.log(chalk.red('\n❌ Job ID required\n'));
|
|
41
|
-
console.log(chalk.gray('Usage: natureco cron run <id>\n'));
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
44
|
-
return runCronJobNow(id);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (action === 'enable') {
|
|
48
|
-
const id = args[0];
|
|
49
|
-
if (!id) {
|
|
50
|
-
console.log(chalk.red('\n❌ Job ID required\n'));
|
|
51
|
-
console.log(chalk.gray('Usage: natureco cron enable <id>\n'));
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
return toggleCronJob(id, true);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (action === 'disable') {
|
|
58
|
-
const id = args[0];
|
|
59
|
-
if (!id) {
|
|
60
|
-
console.log(chalk.red('\n❌ Job ID required\n'));
|
|
61
|
-
console.log(chalk.gray('Usage: natureco cron disable <id>\n'));
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
return toggleCronJob(id, false);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (action === 'start') {
|
|
68
|
-
return startCronDaemon();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (action === 'logs') {
|
|
72
|
-
const id = args[0];
|
|
73
|
-
if (!id) {
|
|
74
|
-
console.log(chalk.red('\n❌ Job ID required\n'));
|
|
75
|
-
console.log(chalk.gray('Usage: natureco cron logs <id>\n'));
|
|
76
|
-
process.exit(1);
|
|
6
|
+
const CRONS_FILE = path.join(os.homedir(), '.natureco', 'crons.json');
|
|
7
|
+
|
|
8
|
+
function loadCrons() {
|
|
9
|
+
try {
|
|
10
|
+
if (!fs.existsSync(CRONS_FILE)) {
|
|
11
|
+
return [];
|
|
77
12
|
}
|
|
78
|
-
return
|
|
13
|
+
return JSON.parse(fs.readFileSync(CRONS_FILE, 'utf-8'));
|
|
14
|
+
} catch {
|
|
15
|
+
return [];
|
|
79
16
|
}
|
|
80
|
-
|
|
81
|
-
console.log(chalk.red(`\n❌ Unknown action: ${action}\n`));
|
|
82
|
-
console.log(chalk.gray('Available actions: list, add, remove, run, enable, disable, start, logs\n'));
|
|
83
|
-
process.exit(1);
|
|
84
17
|
}
|
|
85
18
|
|
|
86
|
-
function
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
console.log(chalk.gray('\nNo cron jobs found.\n'));
|
|
91
|
-
console.log(chalk.gray('Create one with: natureco cron add\n'));
|
|
92
|
-
return;
|
|
19
|
+
function saveCrons(crons) {
|
|
20
|
+
const dir = path.dirname(CRONS_FILE);
|
|
21
|
+
if (!fs.existsSync(dir)) {
|
|
22
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
93
23
|
}
|
|
94
|
-
|
|
95
|
-
console.log(chalk.yellow('\nCron Jobs:\n'));
|
|
96
|
-
|
|
97
|
-
jobs.forEach(job => {
|
|
98
|
-
const status = job.enabled ? chalk.green('✓ enabled') : chalk.gray('✗ disabled');
|
|
99
|
-
console.log(` ${chalk.cyan(job.id)} ${status}`);
|
|
100
|
-
console.log(chalk.white(` ${job.name}`));
|
|
101
|
-
console.log(chalk.gray(` Bot: ${job.botName} | Schedule: ${job.schedule}`));
|
|
102
|
-
console.log(chalk.gray(` Output: ${job.outputType === 'file' ? 'log file' : 'terminal'}`));
|
|
103
|
-
console.log('');
|
|
104
|
-
});
|
|
24
|
+
fs.writeFileSync(CRONS_FILE, JSON.stringify(crons, null, 2), 'utf-8');
|
|
105
25
|
}
|
|
106
26
|
|
|
107
|
-
async function
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
if (!
|
|
111
|
-
console.log(chalk.red('\n❌
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
} catch (err) {
|
|
119
|
-
console.log(chalk.red(`\n❌ Error: ${err.message}\n`));
|
|
120
|
-
process.exit(1);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (!botList || !botList.bots || botList.bots.length === 0) {
|
|
124
|
-
console.log(chalk.gray('No bots found. Create one at https://developers.natureco.me\n'));
|
|
27
|
+
async function cron(args) {
|
|
28
|
+
const action = args[0];
|
|
29
|
+
|
|
30
|
+
if (!action || !['add', 'list', 'remove'].includes(action)) {
|
|
31
|
+
console.log(chalk.red('\n❌ Geçersiz aksiyon\n'));
|
|
32
|
+
console.log(chalk.gray('Kullanım:'));
|
|
33
|
+
console.log(chalk.cyan(' natureco cron add --name <name> --schedule <cron> --action <channel> --target <target> --prompt <prompt>'));
|
|
34
|
+
console.log(chalk.cyan(' natureco cron list'));
|
|
35
|
+
console.log(chalk.cyan(' natureco cron remove --name <name>'));
|
|
36
|
+
console.log(chalk.gray('\nÖrnek:'));
|
|
37
|
+
console.log(chalk.cyan(' natureco cron add --name "bitcoin-fiyat" --schedule "0 9 * * *" --action "whatsapp" --target "+905422842631" --prompt "Bugünkü Bitcoin fiyatını öğren ve kısaca bildir"\n'));
|
|
125
38
|
process.exit(1);
|
|
126
39
|
}
|
|
127
40
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
message: 'Job name:',
|
|
135
|
-
validate: (val) => val.trim() !== '' || 'Name cannot be empty',
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
type: 'input',
|
|
139
|
-
name: 'message',
|
|
140
|
-
message: 'Message to send to bot:',
|
|
141
|
-
validate: (val) => val.trim() !== '' || 'Message cannot be empty',
|
|
142
|
-
},
|
|
143
|
-
{
|
|
144
|
-
type: 'list',
|
|
145
|
-
name: 'botId',
|
|
146
|
-
message: 'Select bot:',
|
|
147
|
-
choices: botList.bots.map(b => ({ name: b.name, value: b.id })),
|
|
148
|
-
},
|
|
149
|
-
{
|
|
150
|
-
type: 'list',
|
|
151
|
-
name: 'scheduleType',
|
|
152
|
-
message: 'Schedule type:',
|
|
153
|
-
choices: [
|
|
154
|
-
{ name: 'Daily at specific time', value: 'daily' },
|
|
155
|
-
{ name: 'Every X hours', value: 'hours' },
|
|
156
|
-
{ name: 'Custom cron expression', value: 'custom' },
|
|
157
|
-
],
|
|
158
|
-
},
|
|
159
|
-
]);
|
|
160
|
-
|
|
161
|
-
let schedule;
|
|
162
|
-
|
|
163
|
-
if (answers.scheduleType === 'daily') {
|
|
164
|
-
const timeAnswer = await inquirer.prompt([
|
|
165
|
-
{
|
|
166
|
-
type: 'input',
|
|
167
|
-
name: 'time',
|
|
168
|
-
message: 'Time (HH:MM):',
|
|
169
|
-
default: '09:00',
|
|
170
|
-
validate: (val) => {
|
|
171
|
-
const match = val.match(/^(\d{1,2}):(\d{2})$/);
|
|
172
|
-
if (!match) return 'Invalid time format. Use HH:MM';
|
|
173
|
-
const hour = parseInt(match[1]);
|
|
174
|
-
const minute = parseInt(match[2]);
|
|
175
|
-
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
|
|
176
|
-
return 'Invalid time';
|
|
177
|
-
}
|
|
178
|
-
return true;
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
]);
|
|
182
|
-
schedule = `daily at ${timeAnswer.time}`;
|
|
183
|
-
} else if (answers.scheduleType === 'hours') {
|
|
184
|
-
const hoursAnswer = await inquirer.prompt([
|
|
185
|
-
{
|
|
186
|
-
type: 'input',
|
|
187
|
-
name: 'hours',
|
|
188
|
-
message: 'Every X hours:',
|
|
189
|
-
default: '1',
|
|
190
|
-
validate: (val) => {
|
|
191
|
-
const num = parseInt(val);
|
|
192
|
-
if (isNaN(num) || num < 1 || num > 24) {
|
|
193
|
-
return 'Enter a number between 1 and 24';
|
|
194
|
-
}
|
|
195
|
-
return true;
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
]);
|
|
199
|
-
schedule = `every ${hoursAnswer.hours} hours`;
|
|
200
|
-
} else {
|
|
201
|
-
const cronAnswer = await inquirer.prompt([
|
|
202
|
-
{
|
|
203
|
-
type: 'input',
|
|
204
|
-
name: 'cron',
|
|
205
|
-
message: 'Cron expression:',
|
|
206
|
-
default: '0 9 * * *',
|
|
207
|
-
validate: (val) => {
|
|
208
|
-
const parsed = parseCronSchedule(val);
|
|
209
|
-
if (!validateCronExpression(parsed)) {
|
|
210
|
-
return 'Invalid cron expression';
|
|
211
|
-
}
|
|
212
|
-
return true;
|
|
213
|
-
},
|
|
214
|
-
},
|
|
215
|
-
]);
|
|
216
|
-
schedule = cronAnswer.cron;
|
|
41
|
+
if (action === 'add') {
|
|
42
|
+
await addCron(args);
|
|
43
|
+
} else if (action === 'list') {
|
|
44
|
+
listCrons();
|
|
45
|
+
} else if (action === 'remove') {
|
|
46
|
+
removeCron(args);
|
|
217
47
|
}
|
|
218
|
-
|
|
219
|
-
const outputAnswer = await inquirer.prompt([
|
|
220
|
-
{
|
|
221
|
-
type: 'list',
|
|
222
|
-
name: 'outputType',
|
|
223
|
-
message: 'Output destination:',
|
|
224
|
-
choices: [
|
|
225
|
-
{ name: 'Save to log file', value: 'file' },
|
|
226
|
-
{ name: 'Print to terminal', value: 'terminal' },
|
|
227
|
-
],
|
|
228
|
-
default: 'file',
|
|
229
|
-
},
|
|
230
|
-
]);
|
|
231
|
-
|
|
232
|
-
const bot = botList.bots.find(b => b.id === answers.botId);
|
|
233
|
-
|
|
234
|
-
const job = addCronJob({
|
|
235
|
-
name: answers.name,
|
|
236
|
-
message: answers.message,
|
|
237
|
-
botId: answers.botId,
|
|
238
|
-
botName: bot.name,
|
|
239
|
-
schedule,
|
|
240
|
-
outputType: outputAnswer.outputType,
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
console.log(chalk.green(`\n✅ Cron job created: ${job.id}\n`));
|
|
244
|
-
console.log(chalk.gray('Start the cron daemon with: natureco cron start\n'));
|
|
245
48
|
}
|
|
246
49
|
|
|
247
|
-
function
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
50
|
+
async function addCron(args) {
|
|
51
|
+
const nameIndex = args.indexOf('--name');
|
|
52
|
+
const scheduleIndex = args.indexOf('--schedule');
|
|
53
|
+
const actionIndex = args.indexOf('--action');
|
|
54
|
+
const targetIndex = args.indexOf('--target');
|
|
55
|
+
const promptIndex = args.indexOf('--prompt');
|
|
56
|
+
|
|
57
|
+
if (nameIndex === -1 || scheduleIndex === -1 || actionIndex === -1 || targetIndex === -1 || promptIndex === -1) {
|
|
58
|
+
console.log(chalk.red('\n❌ Eksik parametre\n'));
|
|
59
|
+
console.log(chalk.gray('Gerekli parametreler: --name, --schedule, --action, --target, --prompt\n'));
|
|
253
60
|
process.exit(1);
|
|
254
61
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
62
|
+
|
|
63
|
+
const name = args[nameIndex + 1];
|
|
64
|
+
const schedule = args[scheduleIndex + 1];
|
|
65
|
+
const action = args[actionIndex + 1];
|
|
66
|
+
const target = args[targetIndex + 1];
|
|
67
|
+
const prompt = args[promptIndex + 1];
|
|
68
|
+
|
|
69
|
+
if (!name || !schedule || !action || !target || !prompt) {
|
|
70
|
+
console.log(chalk.red('\n❌ Parametreler boş olamaz\n'));
|
|
261
71
|
process.exit(1);
|
|
262
72
|
}
|
|
263
73
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
console.log(chalk.red('\n❌ Not logged in. Run "natureco login" first.\n'));
|
|
74
|
+
if (!['whatsapp', 'telegram'].includes(action)) {
|
|
75
|
+
console.log(chalk.red('\n❌ Geçersiz action. Sadece "whatsapp" veya "telegram" kullanılabilir\n'));
|
|
267
76
|
process.exit(1);
|
|
268
77
|
}
|
|
269
78
|
|
|
270
|
-
|
|
271
|
-
|
|
79
|
+
// Validate cron expression
|
|
272
80
|
try {
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
if (job.outputType === 'file') {
|
|
279
|
-
logCronOutput(job.id, output);
|
|
280
|
-
console.log(chalk.green('✅ Job completed. Output saved to log file.\n'));
|
|
281
|
-
} else {
|
|
282
|
-
console.log(chalk.green('✅ Job completed:\n'));
|
|
283
|
-
console.log(chalk.white(reply));
|
|
284
|
-
console.log('');
|
|
81
|
+
const nodeCron = require('node-cron');
|
|
82
|
+
if (!nodeCron.validate(schedule)) {
|
|
83
|
+
console.log(chalk.red('\n❌ Geçersiz cron ifadesi\n'));
|
|
84
|
+
console.log(chalk.gray('Örnek: "0 9 * * *" (her gün saat 09:00)\n'));
|
|
85
|
+
process.exit(1);
|
|
285
86
|
}
|
|
286
87
|
} catch (err) {
|
|
287
|
-
console.log(chalk.red(
|
|
88
|
+
console.log(chalk.red('\n❌ node-cron yüklü değil\n'));
|
|
89
|
+
console.log(chalk.yellow('Yüklemek için:'), chalk.cyan('npm install -g node-cron\n'));
|
|
288
90
|
process.exit(1);
|
|
289
91
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (
|
|
295
|
-
|
|
296
|
-
console.log(chalk.
|
|
297
|
-
} else {
|
|
298
|
-
console.log(chalk.red(`\n❌ Cron job not found: ${id}\n`));
|
|
92
|
+
|
|
93
|
+
const crons = loadCrons();
|
|
94
|
+
|
|
95
|
+
// Check if name already exists
|
|
96
|
+
if (crons.find(c => c.name === name)) {
|
|
97
|
+
console.log(chalk.red('\n❌ Bu isimde bir cron zaten var\n'));
|
|
98
|
+
console.log(chalk.yellow('Önce silin:'), chalk.cyan(`natureco cron remove --name "${name}"\n`));
|
|
299
99
|
process.exit(1);
|
|
300
100
|
}
|
|
101
|
+
|
|
102
|
+
const newCron = {
|
|
103
|
+
name,
|
|
104
|
+
schedule,
|
|
105
|
+
action,
|
|
106
|
+
target,
|
|
107
|
+
prompt,
|
|
108
|
+
createdAt: new Date().toISOString(),
|
|
109
|
+
enabled: true
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
crons.push(newCron);
|
|
113
|
+
saveCrons(crons);
|
|
114
|
+
|
|
115
|
+
console.log(chalk.green('\n✅ Cron eklendi!\n'));
|
|
116
|
+
console.log(chalk.cyan('İsim:'), chalk.white(name));
|
|
117
|
+
console.log(chalk.cyan('Zamanlama:'), chalk.white(schedule));
|
|
118
|
+
console.log(chalk.cyan('Kanal:'), chalk.white(action));
|
|
119
|
+
console.log(chalk.cyan('Hedef:'), chalk.white(target));
|
|
120
|
+
console.log(chalk.cyan('Prompt:'), chalk.white(prompt));
|
|
121
|
+
console.log(chalk.gray('\nCron\'lar gateway başlatıldığında aktif olur.'));
|
|
122
|
+
console.log(chalk.gray('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start\n'));
|
|
301
123
|
}
|
|
302
124
|
|
|
303
|
-
|
|
304
|
-
const
|
|
305
|
-
if (!apiKey) {
|
|
306
|
-
console.log(chalk.red('\n❌ Not logged in. Run "natureco login" first.\n'));
|
|
307
|
-
process.exit(1);
|
|
308
|
-
}
|
|
125
|
+
function listCrons() {
|
|
126
|
+
const crons = loadCrons();
|
|
309
127
|
|
|
310
|
-
|
|
311
|
-
|
|
128
|
+
if (crons.length === 0) {
|
|
129
|
+
console.log(chalk.gray('\n⚪ Kayıtlı cron yok\n'));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
312
132
|
|
|
313
|
-
|
|
314
|
-
const tasks = [];
|
|
133
|
+
console.log(chalk.green(`\n📅 Kayıtlı Cron'lar (${crons.length})\n`));
|
|
315
134
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
const task = cron.schedule(cronExpression, async () => {
|
|
327
|
-
console.log(chalk.yellow(`⏳ Running job: ${job.name}`));
|
|
328
|
-
|
|
329
|
-
try {
|
|
330
|
-
const response = await sendMessage(apiKey, job.botId, job.message, null, '');
|
|
331
|
-
const reply = response.reply || response.message || 'No response';
|
|
332
|
-
|
|
333
|
-
const output = `Job: ${job.name}\nBot: ${job.botName}\nMessage: ${job.message}\nReply: ${reply}`;
|
|
334
|
-
|
|
335
|
-
if (job.outputType === 'file') {
|
|
336
|
-
logCronOutput(job.id, output);
|
|
337
|
-
console.log(chalk.green(`✅ Job completed: ${job.name} (saved to log)`));
|
|
338
|
-
} else {
|
|
339
|
-
console.log(chalk.green(`✅ Job completed: ${job.name}`));
|
|
340
|
-
console.log(chalk.white(reply));
|
|
341
|
-
}
|
|
342
|
-
} catch (err) {
|
|
343
|
-
console.log(chalk.red(`❌ Job failed: ${job.name} - ${err.message}`));
|
|
344
|
-
}
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
tasks.push(task);
|
|
348
|
-
console.log(chalk.cyan(`✓ Scheduled: ${job.name} (${job.schedule})`));
|
|
135
|
+
crons.forEach((c, i) => {
|
|
136
|
+
console.log(chalk.cyan(`${i + 1}. ${c.name}`));
|
|
137
|
+
console.log(chalk.gray(` Zamanlama: ${c.schedule}`));
|
|
138
|
+
console.log(chalk.gray(` Kanal: ${c.action} → ${c.target}`));
|
|
139
|
+
console.log(chalk.gray(` Prompt: ${c.prompt.substring(0, 60)}${c.prompt.length > 60 ? '...' : ''}`));
|
|
140
|
+
console.log(chalk.gray(` Durum: ${c.enabled ? '✅ Aktif' : '❌ Pasif'}`));
|
|
141
|
+
console.log('');
|
|
349
142
|
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function removeCron(args) {
|
|
146
|
+
const nameIndex = args.indexOf('--name');
|
|
350
147
|
|
|
351
|
-
if (
|
|
352
|
-
console.log(chalk.
|
|
353
|
-
process.exit(
|
|
148
|
+
if (nameIndex === -1) {
|
|
149
|
+
console.log(chalk.red('\n❌ --name parametresi gerekli\n'));
|
|
150
|
+
process.exit(1);
|
|
354
151
|
}
|
|
355
152
|
|
|
356
|
-
|
|
153
|
+
const name = args[nameIndex + 1];
|
|
357
154
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
console.log(chalk.gray('\n\n👋 Stopping cron daemon...\n'));
|
|
361
|
-
tasks.forEach(task => task.stop());
|
|
362
|
-
process.exit(0);
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
function showCronLogs(id) {
|
|
367
|
-
const job = getCronJob(id);
|
|
368
|
-
if (!job) {
|
|
369
|
-
console.log(chalk.red(`\n❌ Cron job not found: ${id}\n`));
|
|
155
|
+
if (!name) {
|
|
156
|
+
console.log(chalk.red('\n❌ İsim boş olamaz\n'));
|
|
370
157
|
process.exit(1);
|
|
371
158
|
}
|
|
372
159
|
|
|
373
|
-
const
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
160
|
+
const crons = loadCrons();
|
|
161
|
+
const index = crons.findIndex(c => c.name === name);
|
|
162
|
+
|
|
163
|
+
if (index === -1) {
|
|
164
|
+
console.log(chalk.red('\n❌ Bu isimde bir cron bulunamadı\n'));
|
|
165
|
+
process.exit(1);
|
|
377
166
|
}
|
|
378
167
|
|
|
379
|
-
|
|
380
|
-
|
|
168
|
+
crons.splice(index, 1);
|
|
169
|
+
saveCrons(crons);
|
|
170
|
+
|
|
171
|
+
console.log(chalk.green('\n✅ Cron silindi!\n'));
|
|
172
|
+
console.log(chalk.gray('Gateway çalışıyorsa yeniden başlatın: natureco gateway stop && natureco gateway start\n'));
|
|
381
173
|
}
|
|
382
174
|
|
|
383
|
-
module.exports =
|
|
175
|
+
module.exports = cron;
|
|
@@ -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.
|
|
214
|
+
<div class="version-badge" id="version-badge">v2.9.0</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.
|
|
344
|
+
version: 'v2.9.0',
|
|
345
345
|
bots: cfg.bots || [],
|
|
346
346
|
telegramToken: cfg.telegramToken || null,
|
|
347
347
|
whatsappConnected: cfg.whatsappConnected || false,
|
|
@@ -9,7 +9,18 @@ const LOG_FILE = path.join(os.homedir(), '.natureco', 'gateway.log');
|
|
|
9
9
|
|
|
10
10
|
// WhatsApp imports
|
|
11
11
|
let makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, Browsers;
|
|
12
|
-
|
|
12
|
+
|
|
13
|
+
// Silent logger for Baileys
|
|
14
|
+
const silentLogger = {
|
|
15
|
+
level: 'silent',
|
|
16
|
+
trace: () => {},
|
|
17
|
+
debug: () => {},
|
|
18
|
+
info: () => {},
|
|
19
|
+
warn: () => {},
|
|
20
|
+
error: () => {},
|
|
21
|
+
fatal: () => {},
|
|
22
|
+
child: () => silentLogger
|
|
23
|
+
};
|
|
13
24
|
|
|
14
25
|
// Lazy load Baileys
|
|
15
26
|
function loadBaileys() {
|
|
@@ -127,7 +138,7 @@ async function startGateway() {
|
|
|
127
138
|
|
|
128
139
|
async function runGatewayWorker() {
|
|
129
140
|
// This runs in the background
|
|
130
|
-
log('gateway', 'Starting NatureCo Gateway v2.
|
|
141
|
+
log('gateway', 'Starting NatureCo Gateway v2.9.0...', 'green');
|
|
131
142
|
|
|
132
143
|
// Load config
|
|
133
144
|
const { getConfig } = require('../utils/config');
|
|
@@ -168,6 +179,9 @@ async function runGatewayWorker() {
|
|
|
168
179
|
// Start HTTP server for message sending
|
|
169
180
|
startHttpServer();
|
|
170
181
|
|
|
182
|
+
// Load and start cron jobs
|
|
183
|
+
startCronJobs(config);
|
|
184
|
+
|
|
171
185
|
// Health check every 60 seconds
|
|
172
186
|
setInterval(() => {
|
|
173
187
|
log('gateway', 'health check: OK', 'gray');
|
|
@@ -207,7 +221,7 @@ async function startWhatsAppProvider(sessionDir, config) {
|
|
|
207
221
|
version,
|
|
208
222
|
auth: state,
|
|
209
223
|
printQRInTerminal: false,
|
|
210
|
-
logger:
|
|
224
|
+
logger: silentLogger,
|
|
211
225
|
browser: Browsers.ubuntu('Chrome'),
|
|
212
226
|
connectTimeoutMs: 60000,
|
|
213
227
|
defaultQueryTimeoutMs: 60000,
|
|
@@ -560,6 +574,87 @@ function startHttpServer() {
|
|
|
560
574
|
});
|
|
561
575
|
}
|
|
562
576
|
|
|
577
|
+
function startCronJobs(config) {
|
|
578
|
+
try {
|
|
579
|
+
const nodeCron = require('node-cron');
|
|
580
|
+
const CRONS_FILE = path.join(os.homedir(), '.natureco', 'crons.json');
|
|
581
|
+
|
|
582
|
+
if (!fs.existsSync(CRONS_FILE)) {
|
|
583
|
+
log('cron', 'No cron jobs configured', 'gray');
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const crons = JSON.parse(fs.readFileSync(CRONS_FILE, 'utf-8'));
|
|
588
|
+
const enabledCrons = crons.filter(c => c.enabled);
|
|
589
|
+
|
|
590
|
+
if (enabledCrons.length === 0) {
|
|
591
|
+
log('cron', 'No enabled cron jobs', 'gray');
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
log('cron', `Loading ${enabledCrons.length} cron job(s)...`, 'cyan');
|
|
596
|
+
|
|
597
|
+
enabledCrons.forEach(cronJob => {
|
|
598
|
+
try {
|
|
599
|
+
nodeCron.schedule(cronJob.schedule, async () => {
|
|
600
|
+
log('cron', `Triggered: ${cronJob.name}`, 'yellow');
|
|
601
|
+
|
|
602
|
+
try {
|
|
603
|
+
// Send prompt to AI
|
|
604
|
+
const { sendMessage } = require('../utils/api');
|
|
605
|
+
const conversationId = `cron_${cronJob.name.replace(/\s+/g, '_')}`;
|
|
606
|
+
|
|
607
|
+
log('cron', `Sending prompt to AI...`, 'cyan');
|
|
608
|
+
const response = await sendMessage(null, null, cronJob.prompt, conversationId);
|
|
609
|
+
const reply = response?.reply || response?.message || '';
|
|
610
|
+
|
|
611
|
+
if (!reply) {
|
|
612
|
+
log('cron', `No response from AI`, 'red');
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
log('cron', `AI response received (${reply.length} chars)`, 'green');
|
|
617
|
+
|
|
618
|
+
// Send to target channel
|
|
619
|
+
if (cronJob.action === 'whatsapp') {
|
|
620
|
+
if (!global.whatsappSock) {
|
|
621
|
+
log('cron', `WhatsApp not connected, skipping`, 'red');
|
|
622
|
+
return;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
const normalizedTarget = cronJob.target.replace(/[^\d]/g, '');
|
|
626
|
+
const jid = `${normalizedTarget}@s.whatsapp.net`;
|
|
627
|
+
|
|
628
|
+
await global.whatsappSock.sendMessage(jid, { text: reply });
|
|
629
|
+
log('cron', `Sent to WhatsApp: ${cronJob.target}`, 'green');
|
|
630
|
+
|
|
631
|
+
} else if (cronJob.action === 'telegram') {
|
|
632
|
+
if (!global.telegramBot) {
|
|
633
|
+
log('cron', `Telegram not connected, skipping`, 'red');
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
await global.telegramBot.sendMessage(cronJob.target, reply);
|
|
638
|
+
log('cron', `Sent to Telegram: ${cronJob.target}`, 'green');
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
} catch (err) {
|
|
642
|
+
log('cron', `Error executing ${cronJob.name}: ${err.message}`, 'red');
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
|
|
646
|
+
log('cron', `Scheduled: ${cronJob.name} (${cronJob.schedule})`, 'green');
|
|
647
|
+
|
|
648
|
+
} catch (err) {
|
|
649
|
+
log('cron', `Failed to schedule ${cronJob.name}: ${err.message}`, 'red');
|
|
650
|
+
}
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
} catch (err) {
|
|
654
|
+
log('cron', `Failed to load cron jobs: ${err.message}`, 'red');
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
563
658
|
function stopGateway() {
|
|
564
659
|
if (!fs.existsSync(PID_FILE)) {
|
|
565
660
|
console.log(chalk.gray('\n⚠️ Gateway not running\n'));
|