apexbot 1.0.1 → 1.0.4
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/README.md +127 -146
- package/dist/agent/agentManager.js +65 -18
- package/dist/agent/toolExecutor.js +144 -0
- package/dist/channels/channelManager.js +3 -1
- package/dist/cli/index.js +149 -33
- package/dist/gateway/dashboard.js +182 -266
- package/dist/gateway/index.js +65 -11
- package/dist/index.js +12 -12
- package/dist/skills/index.js +212 -0
- package/dist/skills/obsidian.js +440 -0
- package/dist/skills/reminder.js +430 -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 +66 -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,440 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Obsidian Skill
|
|
4
|
+
*
|
|
5
|
+
* Integration with Obsidian note-taking app.
|
|
6
|
+
* Supports reading, writing, searching notes, and managing daily notes.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
const fs = __importStar(require("fs/promises"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
let vaultPath = '';
|
|
45
|
+
const searchNotesTool = {
|
|
46
|
+
definition: {
|
|
47
|
+
name: 'obsidian_search',
|
|
48
|
+
description: 'Search for notes in Obsidian vault by content or filename.',
|
|
49
|
+
category: 'productivity',
|
|
50
|
+
parameters: [
|
|
51
|
+
{
|
|
52
|
+
name: 'query',
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Search query',
|
|
55
|
+
required: true,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'type',
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Search type: content, filename, tag',
|
|
61
|
+
required: false,
|
|
62
|
+
default: 'content',
|
|
63
|
+
enum: ['content', 'filename', 'tag'],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: 'limit',
|
|
67
|
+
type: 'number',
|
|
68
|
+
description: 'Maximum results',
|
|
69
|
+
required: false,
|
|
70
|
+
default: 10,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
returns: 'List of matching notes',
|
|
74
|
+
},
|
|
75
|
+
async execute(params, context) {
|
|
76
|
+
const { query, type = 'content', limit = 10 } = params;
|
|
77
|
+
if (!vaultPath) {
|
|
78
|
+
return { success: false, error: 'Obsidian vault not configured' };
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const results = [];
|
|
82
|
+
async function searchDir(dir) {
|
|
83
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
84
|
+
for (const entry of entries) {
|
|
85
|
+
if (results.length >= limit)
|
|
86
|
+
return;
|
|
87
|
+
const fullPath = path.join(dir, entry.name);
|
|
88
|
+
const relativePath = path.relative(vaultPath, fullPath);
|
|
89
|
+
// Skip hidden files/folders
|
|
90
|
+
if (entry.name.startsWith('.'))
|
|
91
|
+
continue;
|
|
92
|
+
if (entry.isDirectory()) {
|
|
93
|
+
await searchDir(fullPath);
|
|
94
|
+
}
|
|
95
|
+
else if (entry.name.endsWith('.md')) {
|
|
96
|
+
const noteName = entry.name.replace('.md', '');
|
|
97
|
+
if (type === 'filename') {
|
|
98
|
+
if (noteName.toLowerCase().includes(query.toLowerCase())) {
|
|
99
|
+
results.push({
|
|
100
|
+
name: noteName,
|
|
101
|
+
path: relativePath,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else if (type === 'content' || type === 'tag') {
|
|
106
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
107
|
+
if (type === 'tag') {
|
|
108
|
+
const tagPattern = new RegExp(`#${query}\\b`, 'i');
|
|
109
|
+
if (tagPattern.test(content)) {
|
|
110
|
+
results.push({
|
|
111
|
+
name: noteName,
|
|
112
|
+
path: relativePath,
|
|
113
|
+
preview: content.slice(0, 200),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
if (content.toLowerCase().includes(query.toLowerCase())) {
|
|
119
|
+
const idx = content.toLowerCase().indexOf(query.toLowerCase());
|
|
120
|
+
const start = Math.max(0, idx - 50);
|
|
121
|
+
const end = Math.min(content.length, idx + query.length + 50);
|
|
122
|
+
results.push({
|
|
123
|
+
name: noteName,
|
|
124
|
+
path: relativePath,
|
|
125
|
+
preview: content.slice(start, end),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
await searchDir(vaultPath);
|
|
134
|
+
return {
|
|
135
|
+
success: true,
|
|
136
|
+
data: {
|
|
137
|
+
query,
|
|
138
|
+
type,
|
|
139
|
+
results,
|
|
140
|
+
count: results.length,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
return { success: false, error: error.message };
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
const readNoteTool = {
|
|
150
|
+
definition: {
|
|
151
|
+
name: 'obsidian_read',
|
|
152
|
+
description: 'Read the content of an Obsidian note.',
|
|
153
|
+
category: 'productivity',
|
|
154
|
+
parameters: [
|
|
155
|
+
{
|
|
156
|
+
name: 'name',
|
|
157
|
+
type: 'string',
|
|
158
|
+
description: 'Note name or path (without .md)',
|
|
159
|
+
required: true,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
returns: 'Note content',
|
|
163
|
+
},
|
|
164
|
+
async execute(params, context) {
|
|
165
|
+
const { name } = params;
|
|
166
|
+
if (!vaultPath) {
|
|
167
|
+
return { success: false, error: 'Obsidian vault not configured' };
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
let notePath = name;
|
|
171
|
+
if (!notePath.endsWith('.md')) {
|
|
172
|
+
notePath += '.md';
|
|
173
|
+
}
|
|
174
|
+
const fullPath = path.join(vaultPath, notePath);
|
|
175
|
+
const content = await fs.readFile(fullPath, 'utf-8');
|
|
176
|
+
// Parse frontmatter if present
|
|
177
|
+
let frontmatter = {};
|
|
178
|
+
let body = content;
|
|
179
|
+
if (content.startsWith('---')) {
|
|
180
|
+
const endIdx = content.indexOf('---', 3);
|
|
181
|
+
if (endIdx !== -1) {
|
|
182
|
+
const yamlStr = content.slice(3, endIdx).trim();
|
|
183
|
+
body = content.slice(endIdx + 3).trim();
|
|
184
|
+
// Simple YAML parsing
|
|
185
|
+
yamlStr.split('\n').forEach(line => {
|
|
186
|
+
const [key, ...valueParts] = line.split(':');
|
|
187
|
+
if (key && valueParts.length) {
|
|
188
|
+
frontmatter[key.trim()] = valueParts.join(':').trim();
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
success: true,
|
|
195
|
+
data: {
|
|
196
|
+
name,
|
|
197
|
+
path: notePath,
|
|
198
|
+
frontmatter,
|
|
199
|
+
content: body,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
return { success: false, error: error.message };
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
const writeNoteTool = {
|
|
209
|
+
definition: {
|
|
210
|
+
name: 'obsidian_write',
|
|
211
|
+
description: 'Create or update an Obsidian note.',
|
|
212
|
+
category: 'productivity',
|
|
213
|
+
parameters: [
|
|
214
|
+
{
|
|
215
|
+
name: 'name',
|
|
216
|
+
type: 'string',
|
|
217
|
+
description: 'Note name or path (without .md)',
|
|
218
|
+
required: true,
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: 'content',
|
|
222
|
+
type: 'string',
|
|
223
|
+
description: 'Note content (markdown)',
|
|
224
|
+
required: true,
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'append',
|
|
228
|
+
type: 'boolean',
|
|
229
|
+
description: 'Append to existing note',
|
|
230
|
+
required: false,
|
|
231
|
+
default: false,
|
|
232
|
+
},
|
|
233
|
+
],
|
|
234
|
+
returns: 'Success confirmation',
|
|
235
|
+
},
|
|
236
|
+
async execute(params, context) {
|
|
237
|
+
const { name, content, append = false } = params;
|
|
238
|
+
if (!vaultPath) {
|
|
239
|
+
return { success: false, error: 'Obsidian vault not configured' };
|
|
240
|
+
}
|
|
241
|
+
try {
|
|
242
|
+
let notePath = name;
|
|
243
|
+
if (!notePath.endsWith('.md')) {
|
|
244
|
+
notePath += '.md';
|
|
245
|
+
}
|
|
246
|
+
const fullPath = path.join(vaultPath, notePath);
|
|
247
|
+
// Ensure directory exists
|
|
248
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
249
|
+
if (append) {
|
|
250
|
+
const existing = await fs.readFile(fullPath, 'utf-8').catch(() => '');
|
|
251
|
+
await fs.writeFile(fullPath, existing + '\n' + content);
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
await fs.writeFile(fullPath, content);
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
success: true,
|
|
258
|
+
data: {
|
|
259
|
+
name,
|
|
260
|
+
path: notePath,
|
|
261
|
+
action: append ? 'appended' : 'created',
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
return { success: false, error: error.message };
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
const dailyNoteTool = {
|
|
271
|
+
definition: {
|
|
272
|
+
name: 'obsidian_daily',
|
|
273
|
+
description: 'Get or create today\'s daily note.',
|
|
274
|
+
category: 'productivity',
|
|
275
|
+
parameters: [
|
|
276
|
+
{
|
|
277
|
+
name: 'date',
|
|
278
|
+
type: 'string',
|
|
279
|
+
description: 'Date (YYYY-MM-DD), defaults to today',
|
|
280
|
+
required: false,
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
name: 'append',
|
|
284
|
+
type: 'string',
|
|
285
|
+
description: 'Content to append to daily note',
|
|
286
|
+
required: false,
|
|
287
|
+
},
|
|
288
|
+
],
|
|
289
|
+
returns: 'Daily note content',
|
|
290
|
+
},
|
|
291
|
+
async execute(params, context) {
|
|
292
|
+
const { date, append } = params;
|
|
293
|
+
if (!vaultPath) {
|
|
294
|
+
return { success: false, error: 'Obsidian vault not configured' };
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
const targetDate = date ? new Date(date) : new Date();
|
|
298
|
+
const dateStr = targetDate.toISOString().split('T')[0];
|
|
299
|
+
const notePath = `Daily Notes/${dateStr}.md`;
|
|
300
|
+
const fullPath = path.join(vaultPath, notePath);
|
|
301
|
+
// Ensure directory exists
|
|
302
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
303
|
+
let content;
|
|
304
|
+
try {
|
|
305
|
+
content = await fs.readFile(fullPath, 'utf-8');
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Create new daily note
|
|
309
|
+
content = `# ${targetDate.toLocaleDateString('en-US', {
|
|
310
|
+
weekday: 'long',
|
|
311
|
+
year: 'numeric',
|
|
312
|
+
month: 'long',
|
|
313
|
+
day: 'numeric'
|
|
314
|
+
})}\n\n`;
|
|
315
|
+
await fs.writeFile(fullPath, content);
|
|
316
|
+
}
|
|
317
|
+
if (append) {
|
|
318
|
+
content += '\n' + append;
|
|
319
|
+
await fs.writeFile(fullPath, content);
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
success: true,
|
|
323
|
+
data: {
|
|
324
|
+
date: dateStr,
|
|
325
|
+
path: notePath,
|
|
326
|
+
content,
|
|
327
|
+
},
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
return { success: false, error: error.message };
|
|
332
|
+
}
|
|
333
|
+
},
|
|
334
|
+
};
|
|
335
|
+
const listNotesTool = {
|
|
336
|
+
definition: {
|
|
337
|
+
name: 'obsidian_list',
|
|
338
|
+
description: 'List notes in Obsidian vault.',
|
|
339
|
+
category: 'productivity',
|
|
340
|
+
parameters: [
|
|
341
|
+
{
|
|
342
|
+
name: 'folder',
|
|
343
|
+
type: 'string',
|
|
344
|
+
description: 'Folder to list (default: root)',
|
|
345
|
+
required: false,
|
|
346
|
+
default: '',
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
name: 'recursive',
|
|
350
|
+
type: 'boolean',
|
|
351
|
+
description: 'List recursively',
|
|
352
|
+
required: false,
|
|
353
|
+
default: false,
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
returns: 'List of notes',
|
|
357
|
+
},
|
|
358
|
+
async execute(params, context) {
|
|
359
|
+
const { folder = '', recursive = false } = params;
|
|
360
|
+
if (!vaultPath) {
|
|
361
|
+
return { success: false, error: 'Obsidian vault not configured' };
|
|
362
|
+
}
|
|
363
|
+
try {
|
|
364
|
+
const targetPath = path.join(vaultPath, folder);
|
|
365
|
+
const notes = [];
|
|
366
|
+
async function listDir(dir) {
|
|
367
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
368
|
+
for (const entry of entries) {
|
|
369
|
+
if (entry.name.startsWith('.'))
|
|
370
|
+
continue;
|
|
371
|
+
const fullPath = path.join(dir, entry.name);
|
|
372
|
+
const relativePath = path.relative(vaultPath, fullPath);
|
|
373
|
+
if (entry.isDirectory()) {
|
|
374
|
+
if (recursive) {
|
|
375
|
+
await listDir(fullPath);
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
notes.push({
|
|
379
|
+
name: entry.name,
|
|
380
|
+
path: relativePath,
|
|
381
|
+
isFolder: true,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else if (entry.name.endsWith('.md')) {
|
|
386
|
+
const stat = await fs.stat(fullPath);
|
|
387
|
+
notes.push({
|
|
388
|
+
name: entry.name.replace('.md', ''),
|
|
389
|
+
path: relativePath,
|
|
390
|
+
isFolder: false,
|
|
391
|
+
modified: stat.mtime,
|
|
392
|
+
size: stat.size,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
await listDir(targetPath);
|
|
398
|
+
return {
|
|
399
|
+
success: true,
|
|
400
|
+
data: {
|
|
401
|
+
folder,
|
|
402
|
+
notes,
|
|
403
|
+
count: notes.length,
|
|
404
|
+
},
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
catch (error) {
|
|
408
|
+
return { success: false, error: error.message };
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
};
|
|
412
|
+
const manifest = {
|
|
413
|
+
name: 'obsidian',
|
|
414
|
+
version: '1.0.0',
|
|
415
|
+
description: 'Integration with Obsidian note-taking app',
|
|
416
|
+
category: 'productivity',
|
|
417
|
+
icon: 'notes',
|
|
418
|
+
tools: ['obsidian_search', 'obsidian_read', 'obsidian_write', 'obsidian_daily', 'obsidian_list'],
|
|
419
|
+
config: [
|
|
420
|
+
{
|
|
421
|
+
name: 'vaultPath',
|
|
422
|
+
type: 'string',
|
|
423
|
+
description: 'Path to your Obsidian vault folder',
|
|
424
|
+
required: true,
|
|
425
|
+
},
|
|
426
|
+
],
|
|
427
|
+
};
|
|
428
|
+
const obsidianSkill = {
|
|
429
|
+
manifest,
|
|
430
|
+
tools: [searchNotesTool, readNoteTool, writeNoteTool, dailyNoteTool, listNotesTool],
|
|
431
|
+
async initialize(config) {
|
|
432
|
+
vaultPath = config.vaultPath || '';
|
|
433
|
+
console.log(`[Obsidian] Initialized with vault: ${vaultPath}`);
|
|
434
|
+
},
|
|
435
|
+
async shutdown() {
|
|
436
|
+
vaultPath = '';
|
|
437
|
+
console.log('[Obsidian] Shutdown');
|
|
438
|
+
},
|
|
439
|
+
};
|
|
440
|
+
exports.default = obsidianSkill;
|