apexbot 1.0.2 → 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/dist/agent/agentManager.js +52 -5
- package/dist/agent/toolExecutor.js +144 -0
- package/dist/channels/channelManager.js +3 -1
- package/dist/cli/index.js +127 -0
- package/dist/gateway/index.js +62 -8
- package/dist/skills/index.js +212 -0
- package/dist/skills/obsidian.js +440 -0
- package/dist/skills/reminder.js +430 -0
- package/dist/skills/spotify.js +611 -0
- package/dist/skills/system.js +360 -0
- package/dist/skills/weather.js +144 -0
- package/dist/tools/datetime.js +188 -0
- package/dist/tools/file.js +352 -0
- package/dist/tools/index.js +111 -0
- package/dist/tools/loader.js +68 -0
- package/dist/tools/math.js +248 -0
- package/dist/tools/shell.js +104 -0
- package/dist/tools/web.js +197 -0
- package/package.json +2 -2
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Reminder / Scheduler Skill
|
|
4
|
+
*
|
|
5
|
+
* Schedule reminders, timers, and recurring tasks.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.reminderManager = void 0;
|
|
42
|
+
const events_1 = require("events");
|
|
43
|
+
const fs = __importStar(require("fs/promises"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
class ReminderManager extends events_1.EventEmitter {
|
|
46
|
+
reminders = new Map();
|
|
47
|
+
timers = new Map();
|
|
48
|
+
dataPath = '';
|
|
49
|
+
async initialize(dataPath) {
|
|
50
|
+
this.dataPath = dataPath;
|
|
51
|
+
await this.load();
|
|
52
|
+
this.scheduleAll();
|
|
53
|
+
}
|
|
54
|
+
async load() {
|
|
55
|
+
try {
|
|
56
|
+
const data = await fs.readFile(this.dataPath, 'utf-8');
|
|
57
|
+
const reminders = JSON.parse(data);
|
|
58
|
+
for (const r of reminders) {
|
|
59
|
+
r.triggerAt = new Date(r.triggerAt);
|
|
60
|
+
r.created = new Date(r.created);
|
|
61
|
+
this.reminders.set(r.id, r);
|
|
62
|
+
}
|
|
63
|
+
console.log(`[Reminders] Loaded ${this.reminders.size} reminders`);
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// No existing data
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async save() {
|
|
70
|
+
const data = Array.from(this.reminders.values());
|
|
71
|
+
await fs.writeFile(this.dataPath, JSON.stringify(data, null, 2));
|
|
72
|
+
}
|
|
73
|
+
scheduleAll() {
|
|
74
|
+
for (const reminder of this.reminders.values()) {
|
|
75
|
+
this.scheduleReminder(reminder);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
scheduleReminder(reminder) {
|
|
79
|
+
// Clear existing timer
|
|
80
|
+
const existing = this.timers.get(reminder.id);
|
|
81
|
+
if (existing) {
|
|
82
|
+
clearTimeout(existing);
|
|
83
|
+
}
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
const triggerTime = reminder.triggerAt.getTime();
|
|
86
|
+
const delay = triggerTime - now;
|
|
87
|
+
if (delay < 0) {
|
|
88
|
+
// Past reminder, trigger immediately or skip
|
|
89
|
+
if (reminder.recurring) {
|
|
90
|
+
this.rescheduleRecurring(reminder);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
this.reminders.delete(reminder.id);
|
|
94
|
+
this.save();
|
|
95
|
+
}
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Schedule (max setTimeout is ~24 days, handle longer delays)
|
|
99
|
+
const maxDelay = 2147483647; // ~24.8 days
|
|
100
|
+
const actualDelay = Math.min(delay, maxDelay);
|
|
101
|
+
const timer = setTimeout(() => {
|
|
102
|
+
if (delay > maxDelay) {
|
|
103
|
+
// Reschedule for remaining time
|
|
104
|
+
reminder.triggerAt = new Date(triggerTime);
|
|
105
|
+
this.scheduleReminder(reminder);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
this.triggerReminder(reminder);
|
|
109
|
+
}
|
|
110
|
+
}, actualDelay);
|
|
111
|
+
this.timers.set(reminder.id, timer);
|
|
112
|
+
}
|
|
113
|
+
async triggerReminder(reminder) {
|
|
114
|
+
console.log(`[Reminders] Triggering: ${reminder.id}`);
|
|
115
|
+
this.emit('reminder', reminder);
|
|
116
|
+
if (reminder.recurring) {
|
|
117
|
+
this.rescheduleRecurring(reminder);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.reminders.delete(reminder.id);
|
|
121
|
+
this.timers.delete(reminder.id);
|
|
122
|
+
}
|
|
123
|
+
await this.save();
|
|
124
|
+
}
|
|
125
|
+
rescheduleRecurring(reminder) {
|
|
126
|
+
const { type, interval } = reminder.recurring;
|
|
127
|
+
const newTrigger = new Date(reminder.triggerAt);
|
|
128
|
+
switch (type) {
|
|
129
|
+
case 'daily':
|
|
130
|
+
newTrigger.setDate(newTrigger.getDate() + interval);
|
|
131
|
+
break;
|
|
132
|
+
case 'weekly':
|
|
133
|
+
newTrigger.setDate(newTrigger.getDate() + interval * 7);
|
|
134
|
+
break;
|
|
135
|
+
case 'monthly':
|
|
136
|
+
newTrigger.setMonth(newTrigger.getMonth() + interval);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
reminder.triggerAt = newTrigger;
|
|
140
|
+
this.reminders.set(reminder.id, reminder);
|
|
141
|
+
this.scheduleReminder(reminder);
|
|
142
|
+
}
|
|
143
|
+
add(reminder) {
|
|
144
|
+
const id = `rem_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
145
|
+
const full = {
|
|
146
|
+
...reminder,
|
|
147
|
+
id,
|
|
148
|
+
created: new Date(),
|
|
149
|
+
};
|
|
150
|
+
this.reminders.set(id, full);
|
|
151
|
+
this.scheduleReminder(full);
|
|
152
|
+
this.save();
|
|
153
|
+
return full;
|
|
154
|
+
}
|
|
155
|
+
remove(id) {
|
|
156
|
+
const timer = this.timers.get(id);
|
|
157
|
+
if (timer) {
|
|
158
|
+
clearTimeout(timer);
|
|
159
|
+
this.timers.delete(id);
|
|
160
|
+
}
|
|
161
|
+
const deleted = this.reminders.delete(id);
|
|
162
|
+
if (deleted) {
|
|
163
|
+
this.save();
|
|
164
|
+
}
|
|
165
|
+
return deleted;
|
|
166
|
+
}
|
|
167
|
+
list(userId) {
|
|
168
|
+
let reminders = Array.from(this.reminders.values());
|
|
169
|
+
if (userId) {
|
|
170
|
+
reminders = reminders.filter(r => r.userId === userId);
|
|
171
|
+
}
|
|
172
|
+
return reminders.sort((a, b) => a.triggerAt.getTime() - b.triggerAt.getTime());
|
|
173
|
+
}
|
|
174
|
+
shutdown() {
|
|
175
|
+
for (const timer of this.timers.values()) {
|
|
176
|
+
clearTimeout(timer);
|
|
177
|
+
}
|
|
178
|
+
this.timers.clear();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const reminderManager = new ReminderManager();
|
|
182
|
+
exports.reminderManager = reminderManager;
|
|
183
|
+
// Parse natural language time
|
|
184
|
+
function parseTime(input) {
|
|
185
|
+
const now = new Date();
|
|
186
|
+
const lower = input.toLowerCase().trim();
|
|
187
|
+
// Relative time patterns
|
|
188
|
+
const relativeMatch = lower.match(/^in\s+(\d+)\s+(second|minute|hour|day|week|month)s?$/);
|
|
189
|
+
if (relativeMatch) {
|
|
190
|
+
const amount = parseInt(relativeMatch[1]);
|
|
191
|
+
const unit = relativeMatch[2];
|
|
192
|
+
const result = new Date(now);
|
|
193
|
+
switch (unit) {
|
|
194
|
+
case 'second':
|
|
195
|
+
result.setSeconds(result.getSeconds() + amount);
|
|
196
|
+
break;
|
|
197
|
+
case 'minute':
|
|
198
|
+
result.setMinutes(result.getMinutes() + amount);
|
|
199
|
+
break;
|
|
200
|
+
case 'hour':
|
|
201
|
+
result.setHours(result.getHours() + amount);
|
|
202
|
+
break;
|
|
203
|
+
case 'day':
|
|
204
|
+
result.setDate(result.getDate() + amount);
|
|
205
|
+
break;
|
|
206
|
+
case 'week':
|
|
207
|
+
result.setDate(result.getDate() + amount * 7);
|
|
208
|
+
break;
|
|
209
|
+
case 'month':
|
|
210
|
+
result.setMonth(result.getMonth() + amount);
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
// Tomorrow
|
|
216
|
+
if (lower === 'tomorrow') {
|
|
217
|
+
const result = new Date(now);
|
|
218
|
+
result.setDate(result.getDate() + 1);
|
|
219
|
+
result.setHours(9, 0, 0, 0);
|
|
220
|
+
return result;
|
|
221
|
+
}
|
|
222
|
+
// Time patterns (HH:MM)
|
|
223
|
+
const timeMatch = lower.match(/^(\d{1,2}):(\d{2})(?:\s*(am|pm))?$/);
|
|
224
|
+
if (timeMatch) {
|
|
225
|
+
let hours = parseInt(timeMatch[1]);
|
|
226
|
+
const minutes = parseInt(timeMatch[2]);
|
|
227
|
+
const ampm = timeMatch[3];
|
|
228
|
+
if (ampm === 'pm' && hours < 12)
|
|
229
|
+
hours += 12;
|
|
230
|
+
if (ampm === 'am' && hours === 12)
|
|
231
|
+
hours = 0;
|
|
232
|
+
const result = new Date(now);
|
|
233
|
+
result.setHours(hours, minutes, 0, 0);
|
|
234
|
+
if (result <= now) {
|
|
235
|
+
result.setDate(result.getDate() + 1);
|
|
236
|
+
}
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
// ISO date
|
|
240
|
+
const isoDate = new Date(input);
|
|
241
|
+
if (!isNaN(isoDate.getTime())) {
|
|
242
|
+
return isoDate;
|
|
243
|
+
}
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
const setReminderTool = {
|
|
247
|
+
definition: {
|
|
248
|
+
name: 'reminder_set',
|
|
249
|
+
description: 'Set a reminder for a specific time.',
|
|
250
|
+
category: 'automation',
|
|
251
|
+
parameters: [
|
|
252
|
+
{
|
|
253
|
+
name: 'message',
|
|
254
|
+
type: 'string',
|
|
255
|
+
description: 'Reminder message',
|
|
256
|
+
required: true,
|
|
257
|
+
},
|
|
258
|
+
{
|
|
259
|
+
name: 'time',
|
|
260
|
+
type: 'string',
|
|
261
|
+
description: 'When to remind (e.g., "in 30 minutes", "tomorrow", "14:00", "2024-01-15T14:00:00")',
|
|
262
|
+
required: true,
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
name: 'recurring',
|
|
266
|
+
type: 'string',
|
|
267
|
+
description: 'Recurrence: daily, weekly, monthly',
|
|
268
|
+
required: false,
|
|
269
|
+
enum: ['daily', 'weekly', 'monthly'],
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
returns: 'Reminder confirmation',
|
|
273
|
+
examples: [
|
|
274
|
+
'reminder_set({ message: "Call mom", time: "in 2 hours" })',
|
|
275
|
+
'reminder_set({ message: "Team meeting", time: "14:00", recurring: "daily" })',
|
|
276
|
+
],
|
|
277
|
+
},
|
|
278
|
+
async execute(params, context) {
|
|
279
|
+
const { message, time, recurring } = params;
|
|
280
|
+
if (!message || !time) {
|
|
281
|
+
return { success: false, error: 'Message and time are required' };
|
|
282
|
+
}
|
|
283
|
+
const triggerAt = parseTime(time);
|
|
284
|
+
if (!triggerAt) {
|
|
285
|
+
return { success: false, error: `Could not parse time: ${time}` };
|
|
286
|
+
}
|
|
287
|
+
const reminder = reminderManager.add({
|
|
288
|
+
message,
|
|
289
|
+
triggerAt,
|
|
290
|
+
recurring: recurring ? { type: recurring, interval: 1 } : undefined,
|
|
291
|
+
userId: context.userId,
|
|
292
|
+
channel: context.channel,
|
|
293
|
+
});
|
|
294
|
+
return {
|
|
295
|
+
success: true,
|
|
296
|
+
data: {
|
|
297
|
+
id: reminder.id,
|
|
298
|
+
message: reminder.message,
|
|
299
|
+
triggerAt: reminder.triggerAt.toISOString(),
|
|
300
|
+
recurring: reminder.recurring,
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
const listRemindersTool = {
|
|
306
|
+
definition: {
|
|
307
|
+
name: 'reminder_list',
|
|
308
|
+
description: 'List all active reminders.',
|
|
309
|
+
category: 'automation',
|
|
310
|
+
parameters: [],
|
|
311
|
+
returns: 'List of reminders',
|
|
312
|
+
},
|
|
313
|
+
async execute(params, context) {
|
|
314
|
+
const reminders = reminderManager.list(context.userId);
|
|
315
|
+
return {
|
|
316
|
+
success: true,
|
|
317
|
+
data: {
|
|
318
|
+
reminders: reminders.map(r => ({
|
|
319
|
+
id: r.id,
|
|
320
|
+
message: r.message,
|
|
321
|
+
triggerAt: r.triggerAt.toISOString(),
|
|
322
|
+
recurring: r.recurring,
|
|
323
|
+
})),
|
|
324
|
+
count: reminders.length,
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
},
|
|
328
|
+
};
|
|
329
|
+
const cancelReminderTool = {
|
|
330
|
+
definition: {
|
|
331
|
+
name: 'reminder_cancel',
|
|
332
|
+
description: 'Cancel a reminder.',
|
|
333
|
+
category: 'automation',
|
|
334
|
+
parameters: [
|
|
335
|
+
{
|
|
336
|
+
name: 'id',
|
|
337
|
+
type: 'string',
|
|
338
|
+
description: 'Reminder ID to cancel',
|
|
339
|
+
required: true,
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
returns: 'Cancellation confirmation',
|
|
343
|
+
},
|
|
344
|
+
async execute(params, context) {
|
|
345
|
+
const { id } = params;
|
|
346
|
+
if (!id) {
|
|
347
|
+
return { success: false, error: 'Reminder ID is required' };
|
|
348
|
+
}
|
|
349
|
+
const deleted = reminderManager.remove(id);
|
|
350
|
+
return {
|
|
351
|
+
success: deleted,
|
|
352
|
+
data: deleted ? { id, cancelled: true } : undefined,
|
|
353
|
+
error: deleted ? undefined : `Reminder not found: ${id}`,
|
|
354
|
+
};
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
const timerTool = {
|
|
358
|
+
definition: {
|
|
359
|
+
name: 'timer',
|
|
360
|
+
description: 'Set a countdown timer.',
|
|
361
|
+
category: 'automation',
|
|
362
|
+
parameters: [
|
|
363
|
+
{
|
|
364
|
+
name: 'duration',
|
|
365
|
+
type: 'string',
|
|
366
|
+
description: 'Timer duration (e.g., "5 minutes", "1 hour 30 minutes")',
|
|
367
|
+
required: true,
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
name: 'message',
|
|
371
|
+
type: 'string',
|
|
372
|
+
description: 'Message when timer ends',
|
|
373
|
+
required: false,
|
|
374
|
+
default: 'Timer finished!',
|
|
375
|
+
},
|
|
376
|
+
],
|
|
377
|
+
returns: 'Timer confirmation',
|
|
378
|
+
},
|
|
379
|
+
async execute(params, context) {
|
|
380
|
+
const { duration, message = 'Timer finished!' } = params;
|
|
381
|
+
if (!duration) {
|
|
382
|
+
return { success: false, error: 'Duration is required' };
|
|
383
|
+
}
|
|
384
|
+
const triggerAt = parseTime(`in ${duration}`);
|
|
385
|
+
if (!triggerAt) {
|
|
386
|
+
return { success: false, error: `Could not parse duration: ${duration}` };
|
|
387
|
+
}
|
|
388
|
+
const reminder = reminderManager.add({
|
|
389
|
+
message,
|
|
390
|
+
triggerAt,
|
|
391
|
+
userId: context.userId,
|
|
392
|
+
channel: context.channel,
|
|
393
|
+
});
|
|
394
|
+
const durationMs = triggerAt.getTime() - Date.now();
|
|
395
|
+
const minutes = Math.floor(durationMs / 60000);
|
|
396
|
+
const seconds = Math.floor((durationMs % 60000) / 1000);
|
|
397
|
+
return {
|
|
398
|
+
success: true,
|
|
399
|
+
data: {
|
|
400
|
+
id: reminder.id,
|
|
401
|
+
message: reminder.message,
|
|
402
|
+
duration: `${minutes}m ${seconds}s`,
|
|
403
|
+
endsAt: reminder.triggerAt.toISOString(),
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
},
|
|
407
|
+
};
|
|
408
|
+
const manifest = {
|
|
409
|
+
name: 'reminder',
|
|
410
|
+
version: '1.0.0',
|
|
411
|
+
description: 'Reminders, timers, and scheduled tasks',
|
|
412
|
+
category: 'automation',
|
|
413
|
+
icon: 'alarm',
|
|
414
|
+
tools: ['reminder_set', 'reminder_list', 'reminder_cancel', 'timer'],
|
|
415
|
+
config: [],
|
|
416
|
+
};
|
|
417
|
+
const reminderSkill = {
|
|
418
|
+
manifest,
|
|
419
|
+
tools: [setReminderTool, listRemindersTool, cancelReminderTool, timerTool],
|
|
420
|
+
async initialize(config) {
|
|
421
|
+
const dataPath = config.dataPath || path.join(process.env.HOME || process.env.USERPROFILE || '', '.apexbot', 'reminders.json');
|
|
422
|
+
await reminderManager.initialize(dataPath);
|
|
423
|
+
console.log('[Reminders] Initialized');
|
|
424
|
+
},
|
|
425
|
+
async shutdown() {
|
|
426
|
+
reminderManager.shutdown();
|
|
427
|
+
console.log('[Reminders] Shutdown');
|
|
428
|
+
},
|
|
429
|
+
};
|
|
430
|
+
exports.default = reminderSkill;
|