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.
Files changed (115) hide show
  1. package/README.md +666 -0
  2. package/SOUL.md +104 -0
  3. package/config/hooks.json +14 -0
  4. package/config/mcp.json +145 -0
  5. package/package.json +86 -0
  6. package/skills/.gitkeep +0 -0
  7. package/skills/apple-notes.md +193 -0
  8. package/skills/apple-reminders.md +189 -0
  9. package/skills/camsnap.md +162 -0
  10. package/skills/coding.md +14 -0
  11. package/skills/documents.md +13 -0
  12. package/skills/email.md +13 -0
  13. package/skills/gif-search.md +196 -0
  14. package/skills/healthcheck.md +225 -0
  15. package/skills/image-gen.md +147 -0
  16. package/skills/model-usage.md +182 -0
  17. package/skills/obsidian.md +207 -0
  18. package/skills/pdf.md +211 -0
  19. package/skills/research.md +13 -0
  20. package/skills/skill-creator.md +142 -0
  21. package/skills/spotify.md +149 -0
  22. package/skills/summarize.md +230 -0
  23. package/skills/things.md +199 -0
  24. package/skills/tmux.md +204 -0
  25. package/skills/trello.md +183 -0
  26. package/skills/video-frames.md +202 -0
  27. package/skills/weather.md +127 -0
  28. package/src/a2a/A2AClient.js +136 -0
  29. package/src/a2a/A2AServer.js +316 -0
  30. package/src/a2a/AgentCard.js +79 -0
  31. package/src/agents/SubAgentManager.js +369 -0
  32. package/src/agents/Supervisor.js +192 -0
  33. package/src/channels/BaseChannel.js +104 -0
  34. package/src/channels/DiscordChannel.js +288 -0
  35. package/src/channels/EmailChannel.js +172 -0
  36. package/src/channels/GoogleChatChannel.js +316 -0
  37. package/src/channels/HttpChannel.js +26 -0
  38. package/src/channels/LineChannel.js +168 -0
  39. package/src/channels/SignalChannel.js +186 -0
  40. package/src/channels/SlackChannel.js +329 -0
  41. package/src/channels/TeamsChannel.js +272 -0
  42. package/src/channels/TelegramChannel.js +347 -0
  43. package/src/channels/WhatsAppChannel.js +219 -0
  44. package/src/channels/index.js +198 -0
  45. package/src/cli.js +1267 -0
  46. package/src/config/agentProfiles.js +120 -0
  47. package/src/config/channels.js +32 -0
  48. package/src/config/default.js +206 -0
  49. package/src/config/models.js +123 -0
  50. package/src/config/permissions.js +167 -0
  51. package/src/core/AgentLoop.js +446 -0
  52. package/src/core/Compaction.js +143 -0
  53. package/src/core/CostTracker.js +116 -0
  54. package/src/core/EventBus.js +46 -0
  55. package/src/core/Task.js +67 -0
  56. package/src/core/TaskQueue.js +206 -0
  57. package/src/core/TaskRunner.js +226 -0
  58. package/src/daemon/DaemonManager.js +301 -0
  59. package/src/hooks/HookRunner.js +230 -0
  60. package/src/index.js +482 -0
  61. package/src/mcp/MCPAgentRunner.js +112 -0
  62. package/src/mcp/MCPClient.js +186 -0
  63. package/src/mcp/MCPManager.js +412 -0
  64. package/src/models/ModelRouter.js +180 -0
  65. package/src/safety/AuditLog.js +135 -0
  66. package/src/safety/CircuitBreaker.js +126 -0
  67. package/src/safety/FilesystemGuard.js +169 -0
  68. package/src/safety/GitRollback.js +139 -0
  69. package/src/safety/HumanApproval.js +156 -0
  70. package/src/safety/InputSanitizer.js +72 -0
  71. package/src/safety/PermissionGuard.js +83 -0
  72. package/src/safety/Sandbox.js +70 -0
  73. package/src/safety/SecretScanner.js +100 -0
  74. package/src/safety/SecretVault.js +250 -0
  75. package/src/scheduler/Heartbeat.js +115 -0
  76. package/src/scheduler/Scheduler.js +228 -0
  77. package/src/services/models/outputSchema.js +15 -0
  78. package/src/services/openai.js +25 -0
  79. package/src/services/sessions.js +65 -0
  80. package/src/setup/theme.js +110 -0
  81. package/src/setup/wizard.js +788 -0
  82. package/src/skills/SkillLoader.js +168 -0
  83. package/src/storage/TaskStore.js +69 -0
  84. package/src/systemPrompt.js +526 -0
  85. package/src/tenants/TenantContext.js +19 -0
  86. package/src/tenants/TenantManager.js +379 -0
  87. package/src/tools/ToolRegistry.js +141 -0
  88. package/src/tools/applyPatch.js +144 -0
  89. package/src/tools/browserAutomation.js +223 -0
  90. package/src/tools/createDocument.js +265 -0
  91. package/src/tools/cronTool.js +105 -0
  92. package/src/tools/editFile.js +139 -0
  93. package/src/tools/executeCommand.js +123 -0
  94. package/src/tools/glob.js +67 -0
  95. package/src/tools/grep.js +121 -0
  96. package/src/tools/imageAnalysis.js +120 -0
  97. package/src/tools/index.js +173 -0
  98. package/src/tools/listDirectory.js +47 -0
  99. package/src/tools/manageAgents.js +47 -0
  100. package/src/tools/manageMCP.js +159 -0
  101. package/src/tools/memory.js +478 -0
  102. package/src/tools/messageChannel.js +45 -0
  103. package/src/tools/projectTracker.js +259 -0
  104. package/src/tools/readFile.js +52 -0
  105. package/src/tools/screenCapture.js +112 -0
  106. package/src/tools/searchContent.js +76 -0
  107. package/src/tools/searchFiles.js +75 -0
  108. package/src/tools/sendEmail.js +118 -0
  109. package/src/tools/sendFile.js +63 -0
  110. package/src/tools/textToSpeech.js +161 -0
  111. package/src/tools/transcribeAudio.js +82 -0
  112. package/src/tools/useMCP.js +29 -0
  113. package/src/tools/webFetch.js +150 -0
  114. package/src/tools/webSearch.js +134 -0
  115. 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
+ ];