daemora 1.0.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/README.md +666 -0
- package/SOUL.md +104 -0
- package/config/hooks.json +14 -0
- package/config/mcp.json +145 -0
- package/package.json +86 -0
- package/skills/.gitkeep +0 -0
- package/skills/apple-notes.md +193 -0
- package/skills/apple-reminders.md +189 -0
- package/skills/camsnap.md +162 -0
- package/skills/coding.md +14 -0
- package/skills/documents.md +13 -0
- package/skills/email.md +13 -0
- package/skills/gif-search.md +196 -0
- package/skills/healthcheck.md +225 -0
- package/skills/image-gen.md +147 -0
- package/skills/model-usage.md +182 -0
- package/skills/obsidian.md +207 -0
- package/skills/pdf.md +211 -0
- package/skills/research.md +13 -0
- package/skills/skill-creator.md +142 -0
- package/skills/spotify.md +149 -0
- package/skills/summarize.md +230 -0
- package/skills/things.md +199 -0
- package/skills/tmux.md +204 -0
- package/skills/trello.md +183 -0
- package/skills/video-frames.md +202 -0
- package/skills/weather.md +127 -0
- package/src/a2a/A2AClient.js +136 -0
- package/src/a2a/A2AServer.js +316 -0
- package/src/a2a/AgentCard.js +79 -0
- package/src/agents/SubAgentManager.js +369 -0
- package/src/agents/Supervisor.js +192 -0
- package/src/channels/BaseChannel.js +104 -0
- package/src/channels/DiscordChannel.js +288 -0
- package/src/channels/EmailChannel.js +172 -0
- package/src/channels/GoogleChatChannel.js +316 -0
- package/src/channels/HttpChannel.js +26 -0
- package/src/channels/LineChannel.js +168 -0
- package/src/channels/SignalChannel.js +186 -0
- package/src/channels/SlackChannel.js +329 -0
- package/src/channels/TeamsChannel.js +272 -0
- package/src/channels/TelegramChannel.js +347 -0
- package/src/channels/WhatsAppChannel.js +219 -0
- package/src/channels/index.js +198 -0
- package/src/cli.js +1267 -0
- package/src/config/agentProfiles.js +120 -0
- package/src/config/channels.js +32 -0
- package/src/config/default.js +206 -0
- package/src/config/models.js +123 -0
- package/src/config/permissions.js +167 -0
- package/src/core/AgentLoop.js +446 -0
- package/src/core/Compaction.js +143 -0
- package/src/core/CostTracker.js +116 -0
- package/src/core/EventBus.js +46 -0
- package/src/core/Task.js +67 -0
- package/src/core/TaskQueue.js +206 -0
- package/src/core/TaskRunner.js +226 -0
- package/src/daemon/DaemonManager.js +301 -0
- package/src/hooks/HookRunner.js +230 -0
- package/src/index.js +482 -0
- package/src/mcp/MCPAgentRunner.js +112 -0
- package/src/mcp/MCPClient.js +186 -0
- package/src/mcp/MCPManager.js +412 -0
- package/src/models/ModelRouter.js +180 -0
- package/src/safety/AuditLog.js +135 -0
- package/src/safety/CircuitBreaker.js +126 -0
- package/src/safety/FilesystemGuard.js +169 -0
- package/src/safety/GitRollback.js +139 -0
- package/src/safety/HumanApproval.js +156 -0
- package/src/safety/InputSanitizer.js +72 -0
- package/src/safety/PermissionGuard.js +83 -0
- package/src/safety/Sandbox.js +70 -0
- package/src/safety/SecretScanner.js +100 -0
- package/src/safety/SecretVault.js +250 -0
- package/src/scheduler/Heartbeat.js +115 -0
- package/src/scheduler/Scheduler.js +228 -0
- package/src/services/models/outputSchema.js +15 -0
- package/src/services/openai.js +25 -0
- package/src/services/sessions.js +65 -0
- package/src/setup/theme.js +110 -0
- package/src/setup/wizard.js +788 -0
- package/src/skills/SkillLoader.js +168 -0
- package/src/storage/TaskStore.js +69 -0
- package/src/systemPrompt.js +526 -0
- package/src/tenants/TenantContext.js +19 -0
- package/src/tenants/TenantManager.js +379 -0
- package/src/tools/ToolRegistry.js +141 -0
- package/src/tools/applyPatch.js +144 -0
- package/src/tools/browserAutomation.js +223 -0
- package/src/tools/createDocument.js +265 -0
- package/src/tools/cronTool.js +105 -0
- package/src/tools/editFile.js +139 -0
- package/src/tools/executeCommand.js +123 -0
- package/src/tools/glob.js +67 -0
- package/src/tools/grep.js +121 -0
- package/src/tools/imageAnalysis.js +120 -0
- package/src/tools/index.js +173 -0
- package/src/tools/listDirectory.js +47 -0
- package/src/tools/manageAgents.js +47 -0
- package/src/tools/manageMCP.js +159 -0
- package/src/tools/memory.js +478 -0
- package/src/tools/messageChannel.js +45 -0
- package/src/tools/projectTracker.js +259 -0
- package/src/tools/readFile.js +52 -0
- package/src/tools/screenCapture.js +112 -0
- package/src/tools/searchContent.js +76 -0
- package/src/tools/searchFiles.js +75 -0
- package/src/tools/sendEmail.js +118 -0
- package/src/tools/sendFile.js +63 -0
- package/src/tools/textToSpeech.js +161 -0
- package/src/tools/transcribeAudio.js +82 -0
- package/src/tools/useMCP.js +29 -0
- package/src/tools/webFetch.js +150 -0
- package/src/tools/webSearch.js +134 -0
- package/src/tools/writeFile.js +26 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, existsSync, statSync, watchFile } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { config } from "../config/default.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Skill Loader — auto-discovers .md skill files from the skills/ directory.
|
|
7
|
+
*
|
|
8
|
+
* Each skill file has YAML frontmatter (name, description, triggers)
|
|
9
|
+
* followed by the skill prompt content.
|
|
10
|
+
*
|
|
11
|
+
* Skills are injected into the system prompt when their description
|
|
12
|
+
* matches the current task context.
|
|
13
|
+
*
|
|
14
|
+
* Format:
|
|
15
|
+
* ```markdown
|
|
16
|
+
* ---
|
|
17
|
+
* name: coding
|
|
18
|
+
* description: Use when writing, debugging, or reviewing code
|
|
19
|
+
* triggers: code, function, bug, error, refactor, implement
|
|
20
|
+
* ---
|
|
21
|
+
* You are an expert programmer...
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
class SkillLoader {
|
|
26
|
+
constructor() {
|
|
27
|
+
this.skills = new Map();
|
|
28
|
+
this.loaded = false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Load all skill files from the skills directory.
|
|
33
|
+
*/
|
|
34
|
+
load() {
|
|
35
|
+
const skillsDir = config.skillsDir;
|
|
36
|
+
if (!existsSync(skillsDir)) {
|
|
37
|
+
console.log(`[SkillLoader] No skills directory: ${skillsDir}`);
|
|
38
|
+
this.loaded = true;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const files = readdirSync(skillsDir).filter((f) => f.endsWith(".md"));
|
|
43
|
+
this.skills.clear();
|
|
44
|
+
|
|
45
|
+
for (const file of files) {
|
|
46
|
+
try {
|
|
47
|
+
const filePath = join(skillsDir, file);
|
|
48
|
+
const content = readFileSync(filePath, "utf-8");
|
|
49
|
+
const skill = this.parseSkill(content, file);
|
|
50
|
+
if (skill) {
|
|
51
|
+
this.skills.set(skill.name, skill);
|
|
52
|
+
}
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.log(`[SkillLoader] Error loading ${file}: ${error.message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.loaded = true;
|
|
59
|
+
console.log(
|
|
60
|
+
`[SkillLoader] Loaded ${this.skills.size} skills: ${[...this.skills.keys()].join(", ") || "(none)"}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Parse a skill file with YAML frontmatter.
|
|
66
|
+
*/
|
|
67
|
+
parseSkill(content, filename) {
|
|
68
|
+
const fmMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/);
|
|
69
|
+
if (!fmMatch) {
|
|
70
|
+
// No frontmatter — use filename as name
|
|
71
|
+
return {
|
|
72
|
+
name: filename.replace(".md", ""),
|
|
73
|
+
description: "",
|
|
74
|
+
triggers: [],
|
|
75
|
+
content: content.trim(),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const frontmatter = fmMatch[1];
|
|
80
|
+
const body = fmMatch[2].trim();
|
|
81
|
+
|
|
82
|
+
// Simple YAML parsing (no dependency needed)
|
|
83
|
+
const meta = {};
|
|
84
|
+
for (const line of frontmatter.split("\n")) {
|
|
85
|
+
const colonIdx = line.indexOf(":");
|
|
86
|
+
if (colonIdx > 0) {
|
|
87
|
+
const key = line.slice(0, colonIdx).trim();
|
|
88
|
+
const value = line.slice(colonIdx + 1).trim();
|
|
89
|
+
meta[key] = value;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
name: meta.name || filename.replace(".md", ""),
|
|
95
|
+
description: meta.description || "",
|
|
96
|
+
triggers: meta.triggers
|
|
97
|
+
? meta.triggers.split(",").map((t) => t.trim().toLowerCase())
|
|
98
|
+
: [],
|
|
99
|
+
content: body,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Match skills relevant to a given task/message.
|
|
105
|
+
* Returns skill contents to inject into the system prompt.
|
|
106
|
+
*/
|
|
107
|
+
matchSkills(taskInput) {
|
|
108
|
+
if (!this.loaded) this.load();
|
|
109
|
+
|
|
110
|
+
const input = taskInput.toLowerCase();
|
|
111
|
+
const matched = [];
|
|
112
|
+
|
|
113
|
+
for (const [name, skill] of this.skills) {
|
|
114
|
+
// Check triggers
|
|
115
|
+
const triggerMatch = skill.triggers.some((t) => input.includes(t));
|
|
116
|
+
|
|
117
|
+
// Check description keywords
|
|
118
|
+
const descWords = skill.description.toLowerCase().split(/\s+/);
|
|
119
|
+
const descMatch = descWords.some(
|
|
120
|
+
(w) => w.length > 3 && input.includes(w)
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (triggerMatch || descMatch) {
|
|
124
|
+
matched.push(skill);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return matched;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get skill prompt text for matched skills.
|
|
133
|
+
*/
|
|
134
|
+
getSkillPrompts(taskInput) {
|
|
135
|
+
const matched = this.matchSkills(taskInput);
|
|
136
|
+
if (matched.length === 0) return "";
|
|
137
|
+
|
|
138
|
+
const sections = matched.map(
|
|
139
|
+
(s) =>
|
|
140
|
+
`\n--- Skill: ${s.name} ---\n${s.content}\n--- End Skill ---`
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
return `\n\n## Active Skills\n${sections.join("\n")}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* List all loaded skills.
|
|
148
|
+
*/
|
|
149
|
+
list() {
|
|
150
|
+
if (!this.loaded) this.load();
|
|
151
|
+
return [...this.skills.values()].map((s) => ({
|
|
152
|
+
name: s.name,
|
|
153
|
+
description: s.description,
|
|
154
|
+
triggers: s.triggers,
|
|
155
|
+
}));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Reload skills from disk.
|
|
160
|
+
*/
|
|
161
|
+
reload() {
|
|
162
|
+
this.loaded = false;
|
|
163
|
+
this.load();
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const skillLoader = new SkillLoader();
|
|
168
|
+
export default skillLoader;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { writeFileSync, readFileSync, existsSync, readdirSync } from "fs";
|
|
2
|
+
import { config } from "../config/default.js";
|
|
3
|
+
|
|
4
|
+
const TASKS_DIR = config.tasksDir;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Save a task to disk.
|
|
8
|
+
*/
|
|
9
|
+
export function saveTask(task) {
|
|
10
|
+
const filePath = `${TASKS_DIR}/${task.id}.json`;
|
|
11
|
+
writeFileSync(filePath, JSON.stringify(task, null, 2));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Load a task by ID.
|
|
16
|
+
*/
|
|
17
|
+
export function loadTask(taskId) {
|
|
18
|
+
const filePath = `${TASKS_DIR}/${taskId}.json`;
|
|
19
|
+
if (!existsSync(filePath)) return null;
|
|
20
|
+
return JSON.parse(readFileSync(filePath, "utf-8"));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* List recent tasks (sorted by createdAt descending).
|
|
25
|
+
*/
|
|
26
|
+
export function listTasks({ limit = 20, status = null } = {}) {
|
|
27
|
+
const files = readdirSync(TASKS_DIR).filter((f) => f.endsWith(".json"));
|
|
28
|
+
let tasks = files.map((f) => {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(readFileSync(`${TASKS_DIR}/${f}`, "utf-8"));
|
|
31
|
+
} catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}).filter(Boolean);
|
|
35
|
+
|
|
36
|
+
if (status) {
|
|
37
|
+
tasks = tasks.filter((t) => t.status === status);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
tasks.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
|
|
41
|
+
return tasks.slice(0, limit);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* On startup, find tasks stuck in "running" state and reset to "pending".
|
|
46
|
+
*/
|
|
47
|
+
export function recoverStaleTasks() {
|
|
48
|
+
const files = readdirSync(TASKS_DIR).filter((f) => f.endsWith(".json"));
|
|
49
|
+
let recovered = 0;
|
|
50
|
+
|
|
51
|
+
for (const f of files) {
|
|
52
|
+
try {
|
|
53
|
+
const task = JSON.parse(readFileSync(`${TASKS_DIR}/${f}`, "utf-8"));
|
|
54
|
+
if (task.status === "running") {
|
|
55
|
+
task.status = "pending";
|
|
56
|
+
task.startedAt = null;
|
|
57
|
+
writeFileSync(`${TASKS_DIR}/${f}`, JSON.stringify(task, null, 2));
|
|
58
|
+
recovered++;
|
|
59
|
+
console.log(`[TaskStore] Recovered stale task: ${task.id}`);
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// skip corrupt files
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (recovered > 0) {
|
|
67
|
+
console.log(`[TaskStore] Recovered ${recovered} stale task(s)`);
|
|
68
|
+
}
|
|
69
|
+
}
|