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,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Profiles — tool presets for common sub-agent roles.
|
|
3
|
+
*
|
|
4
|
+
* Rather than giving every sub-agent all 33 tools, profiles provide
|
|
5
|
+
* focused tool sets matched to the task type. Inspired by the research
|
|
6
|
+
* finding that specialized context windows outperform bloated ones.
|
|
7
|
+
*
|
|
8
|
+
* Usage in spawnAgent / parallelAgents:
|
|
9
|
+
* { profile: "coder" } — preset tool list
|
|
10
|
+
* { profile: "researcher", extraTools: ["writeFile"] } — preset + additions
|
|
11
|
+
* { tools: ["readFile", "webSearch"] } — explicit list (overrides profile)
|
|
12
|
+
*
|
|
13
|
+
* spawnAgent and parallelAgents are injected dynamically based on depth — not in profiles.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
export const agentProfiles = {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* researcher — gather, analyze, summarize, produce findings.
|
|
20
|
+
* Reads files, searches web, fetches URLs, analyzes images. Saves findings to files.
|
|
21
|
+
* Does NOT ask the user what to look for — searches until it has enough to answer fully.
|
|
22
|
+
* Produces structured output: facts, sources, analysis, recommendations.
|
|
23
|
+
*/
|
|
24
|
+
researcher: [
|
|
25
|
+
"readFile", "listDirectory", "searchFiles", "searchContent",
|
|
26
|
+
"glob", "grep",
|
|
27
|
+
"webFetch", "webSearch",
|
|
28
|
+
"writeFile", // save research notes and findings to workspace
|
|
29
|
+
"createDocument", // produce reports
|
|
30
|
+
"readMemory", "writeMemory", "searchMemory",
|
|
31
|
+
"imageAnalysis", // analyze charts, diagrams, screenshots, visual data
|
|
32
|
+
"useMCP", // query external sources (GitHub, Notion, Linear, etc.)
|
|
33
|
+
],
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* coder — build, fix, test, verify.
|
|
37
|
+
* Full ownership: writes code, runs builds, starts dev servers, tests UI visually,
|
|
38
|
+
* writes test cases, runs them, fixes failures. Does everything without asking the user.
|
|
39
|
+
*/
|
|
40
|
+
coder: [
|
|
41
|
+
"readFile", "writeFile", "editFile", "listDirectory",
|
|
42
|
+
"searchFiles", "searchContent", "glob", "grep", "applyPatch",
|
|
43
|
+
"executeCommand",
|
|
44
|
+
"webFetch", "webSearch",
|
|
45
|
+
"browserAction", // test web UIs, click, fill forms, navigate
|
|
46
|
+
"imageAnalysis", // analyze screenshots for visual bugs, verify UI looks correct
|
|
47
|
+
"screenCapture", // capture screen when browser isn't sufficient
|
|
48
|
+
"readMemory", "writeMemory", "searchMemory", // learn and apply project conventions
|
|
49
|
+
"projectTracker", // track sub-tasks within complex coding work
|
|
50
|
+
"useMCP",
|
|
51
|
+
],
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* writer — produce polished documents, reports, content.
|
|
55
|
+
* Reads existing content for context, researches via web, produces clean output.
|
|
56
|
+
* Does NOT ask what tone/format to use unless genuinely ambiguous — infers from context.
|
|
57
|
+
* Delivers the final document, not a draft asking for feedback.
|
|
58
|
+
*/
|
|
59
|
+
writer: [
|
|
60
|
+
"readFile", "writeFile", "editFile", "listDirectory",
|
|
61
|
+
"searchFiles", "searchContent", "glob", "grep",
|
|
62
|
+
"webFetch", "webSearch",
|
|
63
|
+
"createDocument",
|
|
64
|
+
"readMemory", "writeMemory", "searchMemory",
|
|
65
|
+
],
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* analyst — process data, run scripts, extract insights, produce output.
|
|
69
|
+
* Shell execution for data processing + web + vision for charts/visuals.
|
|
70
|
+
* Runs scripts, parses output, draws conclusions. Delivers findings, not raw data.
|
|
71
|
+
*/
|
|
72
|
+
analyst: [
|
|
73
|
+
"readFile", "writeFile", "listDirectory", "searchFiles", "searchContent",
|
|
74
|
+
"glob", "grep",
|
|
75
|
+
"webFetch", "webSearch",
|
|
76
|
+
"executeCommand", // run data processing scripts, query CLIs
|
|
77
|
+
"imageAnalysis", // analyze charts, graphs, visual data
|
|
78
|
+
"createDocument", // produce analysis reports
|
|
79
|
+
"readMemory", "writeMemory", "searchMemory",
|
|
80
|
+
],
|
|
81
|
+
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Default tool set for sub-agents spawned without a profile.
|
|
86
|
+
*
|
|
87
|
+
* Covers the majority of tasks while excluding high-blast-radius tools
|
|
88
|
+
* that sub-agents rarely need and that carry side effects beyond task scope:
|
|
89
|
+
* - cron — schedules recurring tasks that outlive the sub-agent
|
|
90
|
+
* - sendEmail — sub-agents shouldn't initiate email
|
|
91
|
+
* - messageChannel — sub-agents shouldn't send messages
|
|
92
|
+
* - screenCapture — sub-agents don't need screen access
|
|
93
|
+
* - manageAgents — sub-agents shouldn't kill/steer other agents
|
|
94
|
+
* - delegateToAgent — A2A from sub-agents is unpredictable
|
|
95
|
+
*
|
|
96
|
+
* spawnAgent and parallelAgents are NOT listed here — they are injected
|
|
97
|
+
* dynamically into sub-agents by SubAgentManager based on recursion depth.
|
|
98
|
+
*/
|
|
99
|
+
export const defaultSubAgentTools = [
|
|
100
|
+
// File
|
|
101
|
+
"readFile", "writeFile", "editFile", "listDirectory",
|
|
102
|
+
"searchFiles", "searchContent", "glob", "grep", "applyPatch",
|
|
103
|
+
// System
|
|
104
|
+
"executeCommand",
|
|
105
|
+
// Web
|
|
106
|
+
"webFetch", "webSearch",
|
|
107
|
+
// Browser
|
|
108
|
+
"browserAction",
|
|
109
|
+
// Documents + Vision
|
|
110
|
+
"createDocument",
|
|
111
|
+
"imageAnalysis",
|
|
112
|
+
// Memory
|
|
113
|
+
"readMemory", "writeMemory", "readDailyLog", "writeDailyLog",
|
|
114
|
+
"searchMemory", "pruneMemory", "listMemoryCategories",
|
|
115
|
+
// Project tracking
|
|
116
|
+
"projectTracker",
|
|
117
|
+
// MCP (via specialist agent — no direct mcp__ tools)
|
|
118
|
+
"manageMCP",
|
|
119
|
+
"useMCP",
|
|
120
|
+
];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel configuration — which input channels are enabled.
|
|
3
|
+
* Actual credentials come from .env via config/default.js.
|
|
4
|
+
*/
|
|
5
|
+
export const channelDefaults = {
|
|
6
|
+
http: {
|
|
7
|
+
name: "HTTP API",
|
|
8
|
+
enabled: true,
|
|
9
|
+
sync: true, // HTTP waits for task completion before responding
|
|
10
|
+
},
|
|
11
|
+
telegram: {
|
|
12
|
+
name: "Telegram",
|
|
13
|
+
enabled: false, // enabled when TELEGRAM_BOT_TOKEN is set
|
|
14
|
+
sync: false,
|
|
15
|
+
},
|
|
16
|
+
whatsapp: {
|
|
17
|
+
name: "WhatsApp",
|
|
18
|
+
enabled: false, // enabled when TWILIO_ACCOUNT_SID is set
|
|
19
|
+
sync: false,
|
|
20
|
+
},
|
|
21
|
+
email: {
|
|
22
|
+
name: "Email",
|
|
23
|
+
enabled: false, // enabled when EMAIL_USER is set
|
|
24
|
+
sync: false,
|
|
25
|
+
pollIntervalSeconds: 60,
|
|
26
|
+
},
|
|
27
|
+
a2a: {
|
|
28
|
+
name: "Agent-to-Agent (A2A)",
|
|
29
|
+
enabled: false, // enabled in Phase 8
|
|
30
|
+
sync: false,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { config as loadEnv } from "dotenv";
|
|
2
|
+
import { join, dirname } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
|
|
5
|
+
loadEnv({ quiet: true });
|
|
6
|
+
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const ROOT_DIR = join(__dirname, "..", "..");
|
|
9
|
+
|
|
10
|
+
export const config = {
|
|
11
|
+
// Server
|
|
12
|
+
port: parseInt(process.env.PORT || "8081", 10),
|
|
13
|
+
|
|
14
|
+
// Paths
|
|
15
|
+
rootDir: ROOT_DIR,
|
|
16
|
+
dataDir: join(ROOT_DIR, "data"),
|
|
17
|
+
sessionsDir: join(ROOT_DIR, "data", "sessions"),
|
|
18
|
+
tasksDir: join(ROOT_DIR, "data", "tasks"),
|
|
19
|
+
memoryDir: join(ROOT_DIR, "data", "memory"),
|
|
20
|
+
auditDir: join(ROOT_DIR, "data", "audit"),
|
|
21
|
+
costsDir: join(ROOT_DIR, "data", "costs"),
|
|
22
|
+
workspacesDir: join(ROOT_DIR, "data", "workspaces"),
|
|
23
|
+
skillsDir: join(ROOT_DIR, "skills"),
|
|
24
|
+
soulPath: join(ROOT_DIR, "SOUL.md"),
|
|
25
|
+
memoryPath: join(ROOT_DIR, "MEMORY.md"),
|
|
26
|
+
|
|
27
|
+
// Default model (provider:model format)
|
|
28
|
+
defaultModel: process.env.DEFAULT_MODEL || "openai:gpt-4.1-mini",
|
|
29
|
+
|
|
30
|
+
// Agent loop
|
|
31
|
+
maxLoops: 40,
|
|
32
|
+
maxSubAgentDepth: 3,
|
|
33
|
+
|
|
34
|
+
// Safety
|
|
35
|
+
permissionTier: process.env.PERMISSION_TIER || "standard",
|
|
36
|
+
|
|
37
|
+
// Cost limits
|
|
38
|
+
maxCostPerTask: parseFloat(process.env.MAX_COST_PER_TASK || "0.50"),
|
|
39
|
+
maxDailyCost: parseFloat(process.env.MAX_DAILY_COST || "10.00"),
|
|
40
|
+
|
|
41
|
+
// Daemon
|
|
42
|
+
daemonMode: process.env.DAEMON_MODE === "true",
|
|
43
|
+
heartbeatIntervalMinutes: parseInt(process.env.HEARTBEAT_INTERVAL_MINUTES || "30", 10),
|
|
44
|
+
|
|
45
|
+
// A2A Security
|
|
46
|
+
a2a: {
|
|
47
|
+
enabled: process.env.A2A_ENABLED === "true", // OFF by default
|
|
48
|
+
authToken: process.env.A2A_AUTH_TOKEN || null, // Bearer token required if set
|
|
49
|
+
allowedAgents: process.env.A2A_ALLOWED_AGENTS
|
|
50
|
+
? process.env.A2A_ALLOWED_AGENTS.split(",").map((s) => s.trim())
|
|
51
|
+
: [], // Allowlist of agent URLs. Empty = block all external agents
|
|
52
|
+
permissionTier: process.env.A2A_PERMISSION_TIER || "minimal", // A2A tasks get minimal permissions by default
|
|
53
|
+
maxCostPerTask: parseFloat(process.env.A2A_MAX_COST || "0.05"), // Much lower budget for external tasks
|
|
54
|
+
rateLimitPerMinute: parseInt(process.env.A2A_RATE_LIMIT || "5", 10), // Max 5 tasks/min from A2A
|
|
55
|
+
blockedTools: ["executeCommand", "writeFile", "editFile", "sendEmail", "spawnAgent"], // Tools blocked for A2A tasks
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
// Filesystem sandboxing
|
|
59
|
+
// ALLOWED_PATHS: comma-separated dirs the agent can access. Empty = unrestricted (global mode).
|
|
60
|
+
// BLOCKED_PATHS: always blocked even if inside ALLOWED_PATHS.
|
|
61
|
+
// RESTRICT_COMMANDS: when true, executeCommand also enforces path scoping (blocks commands
|
|
62
|
+
// whose cwd or referenced absolute paths are outside ALLOWED_PATHS).
|
|
63
|
+
filesystem: {
|
|
64
|
+
allowedPaths: process.env.ALLOWED_PATHS
|
|
65
|
+
? process.env.ALLOWED_PATHS.split(",").map((s) => s.trim()).filter(Boolean)
|
|
66
|
+
: [],
|
|
67
|
+
blockedPaths: process.env.BLOCKED_PATHS
|
|
68
|
+
? process.env.BLOCKED_PATHS.split(",").map((s) => s.trim()).filter(Boolean)
|
|
69
|
+
: [],
|
|
70
|
+
restrictCommands: process.env.RESTRICT_COMMANDS === "true",
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
// Multi-tenant configuration
|
|
74
|
+
// When enabled, each unique channel+userId gets their own tenant record with per-tenant
|
|
75
|
+
// config: model override, allowed/blocked paths, cost limits, tool allowlist, plan tier.
|
|
76
|
+
// Storage: data/tenants/tenants.json | Workspaces: data/tenants/{id}/workspace/
|
|
77
|
+
multiTenant: {
|
|
78
|
+
enabled: process.env.MULTI_TENANT_ENABLED === "true",
|
|
79
|
+
// autoRegister: auto-create a tenant record on first message from any user.
|
|
80
|
+
// Set to false to require manual tenant provisioning via API or CLI.
|
|
81
|
+
autoRegister: process.env.AUTO_REGISTER_TENANTS !== "false", // true by default
|
|
82
|
+
// isolateFilesystem: lock each tenant to their own workspace directory by default
|
|
83
|
+
// (unless they have a custom allowedPaths configured).
|
|
84
|
+
isolateFilesystem: process.env.TENANT_ISOLATE_FILESYSTEM === "true",
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
// Sandbox — OS-level command isolation
|
|
88
|
+
// "process" (default): commands run in the current process, tool-level path guards apply.
|
|
89
|
+
// "docker": commands run inside a Docker container, providing kernel-level isolation.
|
|
90
|
+
// Requires Docker installed. Container gets no network by default (DOCKER_NETWORK=none).
|
|
91
|
+
sandbox: {
|
|
92
|
+
mode: process.env.SANDBOX_MODE || "process", // "process" | "docker"
|
|
93
|
+
dockerImage: process.env.DOCKER_IMAGE || "node:22-alpine",
|
|
94
|
+
dockerMemory: process.env.DOCKER_MEMORY || "512m",
|
|
95
|
+
dockerCpus: process.env.DOCKER_CPUS || "0.5",
|
|
96
|
+
dockerNetwork: process.env.DOCKER_NETWORK || "none",
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// Channels
|
|
100
|
+
// Each channel supports two universal options:
|
|
101
|
+
// allowlist — comma-separated IDs/numbers/usernames in env var (e.g. TELEGRAM_ALLOWLIST="123456789,987654321")
|
|
102
|
+
// If empty or not set → open to everyone. Set this to lock down your bot.
|
|
103
|
+
// model — per-channel model override (e.g. TELEGRAM_MODEL="anthropic:claude-opus-4-6")
|
|
104
|
+
// If not set → global DEFAULT_MODEL is used.
|
|
105
|
+
channels: {
|
|
106
|
+
// HTTP channel is disabled — unauthenticated, see src/channels/index.js
|
|
107
|
+
http: { enabled: false },
|
|
108
|
+
|
|
109
|
+
telegram: {
|
|
110
|
+
enabled: !!process.env.TELEGRAM_BOT_TOKEN,
|
|
111
|
+
token: process.env.TELEGRAM_BOT_TOKEN,
|
|
112
|
+
allowlist: process.env.TELEGRAM_ALLOWLIST
|
|
113
|
+
? process.env.TELEGRAM_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
114
|
+
: [],
|
|
115
|
+
model: process.env.TELEGRAM_MODEL || null,
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
whatsapp: {
|
|
119
|
+
enabled: !!process.env.TWILIO_ACCOUNT_SID,
|
|
120
|
+
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
121
|
+
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
122
|
+
from: process.env.TWILIO_WHATSAPP_FROM,
|
|
123
|
+
allowlist: process.env.WHATSAPP_ALLOWLIST
|
|
124
|
+
? process.env.WHATSAPP_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
125
|
+
: [],
|
|
126
|
+
model: process.env.WHATSAPP_MODEL || null,
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
email: {
|
|
130
|
+
enabled: !!process.env.EMAIL_USER,
|
|
131
|
+
imap: {
|
|
132
|
+
host: process.env.EMAIL_IMAP_HOST || "imap.gmail.com",
|
|
133
|
+
port: parseInt(process.env.EMAIL_IMAP_PORT || "993", 10),
|
|
134
|
+
},
|
|
135
|
+
smtp: {
|
|
136
|
+
host: process.env.EMAIL_SMTP_HOST || "smtp.gmail.com",
|
|
137
|
+
port: parseInt(process.env.EMAIL_SMTP_PORT || "587", 10),
|
|
138
|
+
},
|
|
139
|
+
user: process.env.EMAIL_USER,
|
|
140
|
+
password: process.env.EMAIL_PASSWORD,
|
|
141
|
+
allowlist: process.env.EMAIL_ALLOWLIST
|
|
142
|
+
? process.env.EMAIL_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
143
|
+
: [],
|
|
144
|
+
model: process.env.EMAIL_MODEL || null,
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
discord: {
|
|
148
|
+
enabled: !!process.env.DISCORD_BOT_TOKEN,
|
|
149
|
+
token: process.env.DISCORD_BOT_TOKEN,
|
|
150
|
+
allowlist: process.env.DISCORD_ALLOWLIST
|
|
151
|
+
? process.env.DISCORD_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
152
|
+
: [],
|
|
153
|
+
model: process.env.DISCORD_MODEL || null,
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
slack: {
|
|
157
|
+
enabled: !!(process.env.SLACK_BOT_TOKEN && process.env.SLACK_APP_TOKEN),
|
|
158
|
+
botToken: process.env.SLACK_BOT_TOKEN,
|
|
159
|
+
appToken: process.env.SLACK_APP_TOKEN,
|
|
160
|
+
allowlist: process.env.SLACK_ALLOWLIST
|
|
161
|
+
? process.env.SLACK_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
162
|
+
: [],
|
|
163
|
+
model: process.env.SLACK_MODEL || null,
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
line: {
|
|
167
|
+
enabled: !!(process.env.LINE_CHANNEL_ACCESS_TOKEN && process.env.LINE_CHANNEL_SECRET),
|
|
168
|
+
accessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN,
|
|
169
|
+
channelSecret: process.env.LINE_CHANNEL_SECRET,
|
|
170
|
+
allowlist: process.env.LINE_ALLOWLIST
|
|
171
|
+
? process.env.LINE_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
172
|
+
: [],
|
|
173
|
+
model: process.env.LINE_MODEL || null,
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
signal: {
|
|
177
|
+
enabled: !!(process.env.SIGNAL_CLI_URL && process.env.SIGNAL_PHONE_NUMBER),
|
|
178
|
+
cliUrl: process.env.SIGNAL_CLI_URL,
|
|
179
|
+
phoneNumber: process.env.SIGNAL_PHONE_NUMBER,
|
|
180
|
+
allowlist: process.env.SIGNAL_ALLOWLIST
|
|
181
|
+
? process.env.SIGNAL_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
182
|
+
: [],
|
|
183
|
+
model: process.env.SIGNAL_MODEL || null,
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
teams: {
|
|
187
|
+
enabled: !!(process.env.TEAMS_APP_ID && process.env.TEAMS_APP_PASSWORD),
|
|
188
|
+
appId: process.env.TEAMS_APP_ID,
|
|
189
|
+
appPassword: process.env.TEAMS_APP_PASSWORD,
|
|
190
|
+
allowlist: process.env.TEAMS_ALLOWLIST
|
|
191
|
+
? process.env.TEAMS_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
192
|
+
: [],
|
|
193
|
+
model: process.env.TEAMS_MODEL || null,
|
|
194
|
+
},
|
|
195
|
+
|
|
196
|
+
googlechat: {
|
|
197
|
+
enabled: !!process.env.GOOGLE_CHAT_SERVICE_ACCOUNT,
|
|
198
|
+
serviceAccount: process.env.GOOGLE_CHAT_SERVICE_ACCOUNT || null,
|
|
199
|
+
projectNumber: process.env.GOOGLE_CHAT_PROJECT_NUMBER || null,
|
|
200
|
+
allowlist: process.env.GOOGLE_CHAT_ALLOWLIST
|
|
201
|
+
? process.env.GOOGLE_CHAT_ALLOWLIST.split(",").map((s) => s.trim()).filter(Boolean)
|
|
202
|
+
: [],
|
|
203
|
+
model: process.env.GOOGLE_CHAT_MODEL || null,
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model registry — metadata for all supported models.
|
|
3
|
+
* Used by ModelRouter for selection, cost tracking, and compaction thresholds.
|
|
4
|
+
*/
|
|
5
|
+
export const models = {
|
|
6
|
+
// OpenAI
|
|
7
|
+
"openai:gpt-4.1-mini": {
|
|
8
|
+
provider: "openai",
|
|
9
|
+
model: "gpt-4.1-mini",
|
|
10
|
+
contextWindow: 128_000,
|
|
11
|
+
compactAt: 90_000,
|
|
12
|
+
costPer1kInput: 0.0004,
|
|
13
|
+
costPer1kOutput: 0.0016,
|
|
14
|
+
capabilities: ["text", "tools", "structured-output"],
|
|
15
|
+
tier: "cheap",
|
|
16
|
+
},
|
|
17
|
+
"openai:gpt-4.1": {
|
|
18
|
+
provider: "openai",
|
|
19
|
+
model: "gpt-4.1",
|
|
20
|
+
contextWindow: 128_000,
|
|
21
|
+
compactAt: 90_000,
|
|
22
|
+
costPer1kInput: 0.002,
|
|
23
|
+
costPer1kOutput: 0.008,
|
|
24
|
+
capabilities: ["text", "tools", "structured-output"],
|
|
25
|
+
tier: "standard",
|
|
26
|
+
},
|
|
27
|
+
"openai:o3-mini": {
|
|
28
|
+
provider: "openai",
|
|
29
|
+
model: "o3-mini",
|
|
30
|
+
contextWindow: 200_000,
|
|
31
|
+
compactAt: 140_000,
|
|
32
|
+
costPer1kInput: 0.0011,
|
|
33
|
+
costPer1kOutput: 0.0044,
|
|
34
|
+
capabilities: ["text", "tools", "reasoning"],
|
|
35
|
+
tier: "standard",
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
// Anthropic
|
|
39
|
+
"anthropic:claude-sonnet-4-6": {
|
|
40
|
+
provider: "anthropic",
|
|
41
|
+
model: "claude-sonnet-4-6",
|
|
42
|
+
contextWindow: 200_000,
|
|
43
|
+
compactAt: 140_000,
|
|
44
|
+
costPer1kInput: 0.003,
|
|
45
|
+
costPer1kOutput: 0.015,
|
|
46
|
+
capabilities: ["text", "tools", "structured-output"],
|
|
47
|
+
tier: "standard",
|
|
48
|
+
},
|
|
49
|
+
"anthropic:claude-opus-4-6": {
|
|
50
|
+
provider: "anthropic",
|
|
51
|
+
model: "claude-opus-4-6",
|
|
52
|
+
contextWindow: 200_000,
|
|
53
|
+
compactAt: 140_000,
|
|
54
|
+
costPer1kInput: 0.015,
|
|
55
|
+
costPer1kOutput: 0.075,
|
|
56
|
+
capabilities: ["text", "tools", "structured-output"],
|
|
57
|
+
tier: "expensive",
|
|
58
|
+
},
|
|
59
|
+
"anthropic:claude-haiku-4-5": {
|
|
60
|
+
provider: "anthropic",
|
|
61
|
+
model: "claude-haiku-4-5",
|
|
62
|
+
contextWindow: 200_000,
|
|
63
|
+
compactAt: 140_000,
|
|
64
|
+
costPer1kInput: 0.0008,
|
|
65
|
+
costPer1kOutput: 0.004,
|
|
66
|
+
capabilities: ["text", "tools", "structured-output"],
|
|
67
|
+
tier: "cheap",
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
// Google
|
|
71
|
+
"google:gemini-2.0-flash": {
|
|
72
|
+
provider: "google",
|
|
73
|
+
model: "gemini-2.0-flash",
|
|
74
|
+
contextWindow: 1_000_000,
|
|
75
|
+
compactAt: 700_000,
|
|
76
|
+
costPer1kInput: 0.0001,
|
|
77
|
+
costPer1kOutput: 0.0004,
|
|
78
|
+
capabilities: ["text", "tools", "structured-output"],
|
|
79
|
+
tier: "cheap",
|
|
80
|
+
},
|
|
81
|
+
|
|
82
|
+
// Ollama (local — no cost)
|
|
83
|
+
"ollama:llama3": {
|
|
84
|
+
provider: "ollama",
|
|
85
|
+
model: "llama3",
|
|
86
|
+
contextWindow: 8_192,
|
|
87
|
+
compactAt: 5_600,
|
|
88
|
+
costPer1kInput: 0,
|
|
89
|
+
costPer1kOutput: 0,
|
|
90
|
+
capabilities: ["text"],
|
|
91
|
+
tier: "free",
|
|
92
|
+
},
|
|
93
|
+
"ollama:llama3.1": {
|
|
94
|
+
provider: "ollama",
|
|
95
|
+
model: "llama3.1",
|
|
96
|
+
contextWindow: 128_000,
|
|
97
|
+
compactAt: 90_000,
|
|
98
|
+
costPer1kInput: 0,
|
|
99
|
+
costPer1kOutput: 0,
|
|
100
|
+
capabilities: ["text", "tools"],
|
|
101
|
+
tier: "free",
|
|
102
|
+
},
|
|
103
|
+
"ollama:qwen2.5-coder": {
|
|
104
|
+
provider: "ollama",
|
|
105
|
+
model: "qwen2.5-coder",
|
|
106
|
+
contextWindow: 32_000,
|
|
107
|
+
compactAt: 22_000,
|
|
108
|
+
costPer1kInput: 0,
|
|
109
|
+
costPer1kOutput: 0,
|
|
110
|
+
capabilities: ["text", "tools"],
|
|
111
|
+
tier: "free",
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Fallback chains — if preferred model fails, try next in chain.
|
|
117
|
+
*/
|
|
118
|
+
export const fallbackChains = {
|
|
119
|
+
cheap: ["openai:gpt-4.1-mini", "anthropic:claude-haiku-4-5", "google:gemini-2.0-flash"],
|
|
120
|
+
standard: ["openai:gpt-4.1", "anthropic:claude-sonnet-4-6", "openai:gpt-4.1-mini"],
|
|
121
|
+
expensive: ["anthropic:claude-opus-4-6", "anthropic:claude-sonnet-4-6", "openai:gpt-4.1"],
|
|
122
|
+
local: ["ollama:llama3.1", "ollama:qwen2.5-coder", "ollama:llama3"],
|
|
123
|
+
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission tier definitions.
|
|
3
|
+
* Each tier specifies which tools are allowed.
|
|
4
|
+
* Tiers are cumulative: standard includes minimal, full includes standard.
|
|
5
|
+
*/
|
|
6
|
+
export const permissionTiers = {
|
|
7
|
+
minimal: {
|
|
8
|
+
name: "Minimal (Read-Only)",
|
|
9
|
+
description: "Agent can read files, search, and browse the web — no writes, no shell, no communication.",
|
|
10
|
+
allowedTools: [
|
|
11
|
+
// File reads
|
|
12
|
+
"readFile",
|
|
13
|
+
"listDirectory",
|
|
14
|
+
"searchFiles",
|
|
15
|
+
"searchContent",
|
|
16
|
+
"glob",
|
|
17
|
+
"grep",
|
|
18
|
+
// Web reads
|
|
19
|
+
"webFetch",
|
|
20
|
+
"webSearch",
|
|
21
|
+
// Memory reads
|
|
22
|
+
"readMemory",
|
|
23
|
+
"readDailyLog",
|
|
24
|
+
"searchMemory",
|
|
25
|
+
"listMemoryCategories",
|
|
26
|
+
// Vision (read-only)
|
|
27
|
+
"imageAnalysis",
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
standard: {
|
|
31
|
+
name: "Standard",
|
|
32
|
+
description: "Agent can read + write files, run commands, use browser, and manage memory.",
|
|
33
|
+
allowedTools: [
|
|
34
|
+
// All minimal tools
|
|
35
|
+
"readFile",
|
|
36
|
+
"listDirectory",
|
|
37
|
+
"searchFiles",
|
|
38
|
+
"searchContent",
|
|
39
|
+
"glob",
|
|
40
|
+
"grep",
|
|
41
|
+
"webFetch",
|
|
42
|
+
"webSearch",
|
|
43
|
+
"readMemory",
|
|
44
|
+
"readDailyLog",
|
|
45
|
+
"searchMemory",
|
|
46
|
+
"listMemoryCategories",
|
|
47
|
+
"imageAnalysis",
|
|
48
|
+
// Write tools
|
|
49
|
+
"writeFile",
|
|
50
|
+
"editFile",
|
|
51
|
+
"applyPatch",
|
|
52
|
+
"createDocument",
|
|
53
|
+
"executeCommand",
|
|
54
|
+
"browserAction",
|
|
55
|
+
// Memory writes
|
|
56
|
+
"writeMemory",
|
|
57
|
+
"writeDailyLog",
|
|
58
|
+
"pruneMemory",
|
|
59
|
+
// Screen
|
|
60
|
+
"screenCapture",
|
|
61
|
+
// Project tracking
|
|
62
|
+
"projectTracker",
|
|
63
|
+
// MCP inspection (read-only — no side effects)
|
|
64
|
+
"manageMCP",
|
|
65
|
+
],
|
|
66
|
+
},
|
|
67
|
+
full: {
|
|
68
|
+
name: "Full Access",
|
|
69
|
+
description: "Unrestricted access to all tools including email, messaging, sub-agents, and scheduling.",
|
|
70
|
+
allowedTools: [
|
|
71
|
+
// All standard tools
|
|
72
|
+
"readFile",
|
|
73
|
+
"listDirectory",
|
|
74
|
+
"searchFiles",
|
|
75
|
+
"searchContent",
|
|
76
|
+
"glob",
|
|
77
|
+
"grep",
|
|
78
|
+
"webFetch",
|
|
79
|
+
"webSearch",
|
|
80
|
+
"readMemory",
|
|
81
|
+
"readDailyLog",
|
|
82
|
+
"searchMemory",
|
|
83
|
+
"listMemoryCategories",
|
|
84
|
+
"imageAnalysis",
|
|
85
|
+
"writeFile",
|
|
86
|
+
"editFile",
|
|
87
|
+
"applyPatch",
|
|
88
|
+
"createDocument",
|
|
89
|
+
"executeCommand",
|
|
90
|
+
"browserAction",
|
|
91
|
+
"writeMemory",
|
|
92
|
+
"writeDailyLog",
|
|
93
|
+
"pruneMemory",
|
|
94
|
+
"screenCapture",
|
|
95
|
+
// Full-only: communication
|
|
96
|
+
"sendEmail",
|
|
97
|
+
"messageChannel",
|
|
98
|
+
// Full-only: agents
|
|
99
|
+
"spawnAgent",
|
|
100
|
+
"parallelAgents",
|
|
101
|
+
"delegateToAgent",
|
|
102
|
+
"manageAgents",
|
|
103
|
+
"manageMCP",
|
|
104
|
+
"useMCP",
|
|
105
|
+
// Full-only: automation
|
|
106
|
+
"cron",
|
|
107
|
+
// Project tracking
|
|
108
|
+
"projectTracker",
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Commands that are ALWAYS blocked regardless of permission tier.
|
|
115
|
+
*/
|
|
116
|
+
export const blockedCommands = [
|
|
117
|
+
// Destructive file operations
|
|
118
|
+
/rm\s+-rf\s+\//,
|
|
119
|
+
/rm\s+-rf\s+~/,
|
|
120
|
+
/rm\s+-rf\s+\.\s*$/,
|
|
121
|
+
/sudo\s+rm/,
|
|
122
|
+
/rm\s+--no-preserve-root/,
|
|
123
|
+
/mkfs\./,
|
|
124
|
+
/dd\s+if=/,
|
|
125
|
+
// Fork bombs and process attacks
|
|
126
|
+
/:\(\)\s*\{\s*:\|:\s*&\s*\}\s*;/,
|
|
127
|
+
// Permission escalation
|
|
128
|
+
/chmod\s+777\s+\//,
|
|
129
|
+
/chmod\s+-R\s+777/,
|
|
130
|
+
/chown.*\/etc/,
|
|
131
|
+
/sudo\s+chmod/,
|
|
132
|
+
/sudo\s+chown/,
|
|
133
|
+
// Device and partition attacks
|
|
134
|
+
/>\s*\/dev\/sda/,
|
|
135
|
+
/>\s*\/dev\/nvme/,
|
|
136
|
+
// Remote code execution via pipe
|
|
137
|
+
/curl.*\|\s*sh/,
|
|
138
|
+
/wget.*\|\s*sh/,
|
|
139
|
+
/curl.*\|\s*bash/,
|
|
140
|
+
/wget.*\|\s*bash/,
|
|
141
|
+
/curl.*\|\s*python/,
|
|
142
|
+
/wget.*\|\s*python/,
|
|
143
|
+
// System shutdown/reboot
|
|
144
|
+
/\bshutdown\b/,
|
|
145
|
+
/\breboot\b/,
|
|
146
|
+
/\binit\s+0\b/,
|
|
147
|
+
/\bhalt\b/,
|
|
148
|
+
/\bpoweroff\b/,
|
|
149
|
+
// Process killing
|
|
150
|
+
/kill\s+-9\s+1\b/,
|
|
151
|
+
/killall\s+-9/,
|
|
152
|
+
// Sensitive file reads via commands
|
|
153
|
+
/cat\s+.*\/etc\/shadow/,
|
|
154
|
+
/cat\s+.*\.ssh\/id_/,
|
|
155
|
+
/cat\s+.*\.vault\.enc/,
|
|
156
|
+
/cat\s+.*\.env\b/,
|
|
157
|
+
// Environment variable dump (can leak secrets)
|
|
158
|
+
/^\s*env\s*$/,
|
|
159
|
+
/^\s*printenv\s*$/,
|
|
160
|
+
/^\s*set\s*$/,
|
|
161
|
+
// Network attacks
|
|
162
|
+
/\bnmap\b/,
|
|
163
|
+
/\bnetcat\b|\bnc\s+-/,
|
|
164
|
+
// History access (can contain secrets)
|
|
165
|
+
/cat\s+.*\.bash_history/,
|
|
166
|
+
/cat\s+.*\.zsh_history/,
|
|
167
|
+
];
|