groove-dev 0.16.3 → 0.17.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 +18 -16
- package/node_modules/@groove-dev/daemon/integrations-registry.json +321 -0
- package/node_modules/@groove-dev/daemon/src/api.js +152 -0
- package/node_modules/@groove-dev/daemon/src/index.js +13 -1
- package/node_modules/@groove-dev/daemon/src/integrations.js +389 -0
- package/node_modules/@groove-dev/daemon/src/introducer.js +23 -0
- package/node_modules/@groove-dev/daemon/src/process.js +59 -0
- package/node_modules/@groove-dev/daemon/src/registry.js +2 -1
- package/node_modules/@groove-dev/daemon/src/scheduler.js +336 -0
- package/node_modules/@groove-dev/daemon/src/terminal-pty.js +119 -54
- package/node_modules/@groove-dev/daemon/src/validate.js +10 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-C5k-qSwi.js +153 -0
- package/node_modules/@groove-dev/gui/dist/index.html +1 -1
- package/node_modules/@groove-dev/gui/src/App.jsx +6 -0
- package/node_modules/@groove-dev/gui/src/components/SpawnPanel.jsx +98 -7
- package/node_modules/@groove-dev/gui/src/components/Terminal.jsx +29 -12
- package/node_modules/@groove-dev/gui/src/views/IntegrationsStore.jsx +954 -0
- package/node_modules/@groove-dev/gui/src/views/ScheduleManager.jsx +614 -0
- package/package.json +2 -2
- package/packages/daemon/integrations-registry.json +321 -0
- package/packages/daemon/src/api.js +152 -0
- package/packages/daemon/src/index.js +13 -1
- package/packages/daemon/src/integrations.js +389 -0
- package/packages/daemon/src/introducer.js +23 -0
- package/packages/daemon/src/process.js +59 -0
- package/packages/daemon/src/registry.js +2 -1
- package/packages/daemon/src/scheduler.js +336 -0
- package/packages/daemon/src/terminal-pty.js +119 -54
- package/packages/daemon/src/validate.js +10 -0
- package/packages/gui/dist/assets/index-C5k-qSwi.js +153 -0
- package/packages/gui/dist/index.html +1 -1
- package/packages/gui/src/App.jsx +6 -0
- package/packages/gui/src/components/SpawnPanel.jsx +98 -7
- package/packages/gui/src/components/Terminal.jsx +29 -12
- package/packages/gui/src/views/IntegrationsStore.jsx +954 -0
- package/packages/gui/src/views/ScheduleManager.jsx +614 -0
- package/node_modules/@groove-dev/gui/dist/assets/index-CFeltwTB.js +0 -153
- package/packages/gui/dist/assets/index-CFeltwTB.js +0 -153
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# groove
|
|
2
2
|
|
|
3
3
|
**Orchestrate your AI coding agents. Stop losing context.**
|
|
4
4
|
|
|
@@ -12,7 +12,7 @@ npm i -g groove-dev
|
|
|
12
12
|
groove start
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
The GUI opens at `http://localhost:31415`. On a VPS?
|
|
15
|
+
The GUI opens at `http://localhost:31415`. On a VPS? groove detects it and tells you exactly what to do.
|
|
16
16
|
|
|
17
17
|
---
|
|
18
18
|
|
|
@@ -27,7 +27,7 @@ AI coding agents waste your money and lose their way:
|
|
|
27
27
|
|
|
28
28
|
## The Solution
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
groove sits between you and your AI coding agents. It doesn't replace them — it makes them work together.
|
|
31
31
|
|
|
32
32
|
### Zero Cold-Start (The Journalist)
|
|
33
33
|
|
|
@@ -35,7 +35,7 @@ A background AI continuously watches all agent activity and synthesizes it into
|
|
|
35
35
|
|
|
36
36
|
### Infinite Sessions (Context Rotation)
|
|
37
37
|
|
|
38
|
-
Instead of letting agents fill their context window until they degrade,
|
|
38
|
+
Instead of letting agents fill their context window until they degrade, groove detects quality decline — error spikes, circular refactors, file churn — and automatically rotates: kill the session, spawn fresh, feed it the Journalist's context. The agent picks up exactly where it left off with a clean window. No compaction. No drift. Works at any codebase scale.
|
|
39
39
|
|
|
40
40
|
### AI Project Manager
|
|
41
41
|
|
|
@@ -47,7 +47,7 @@ Spawn a planner, describe your project. The planner writes a detailed plan and r
|
|
|
47
47
|
|
|
48
48
|
### Workspaces (Large Codebase Support)
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
groove auto-detects monorepo workspaces (npm, pnpm, lerna) and lets you spawn each agent in its own subdirectory. A frontend agent only sees `packages/frontend/`. A backend agent only sees `packages/backend/`. No wasted context on irrelevant code.
|
|
51
51
|
|
|
52
52
|
- **Codebase indexer** — scans project structure on start, gives every agent instant orientation
|
|
53
53
|
- **Architecture injection** — auto-detects `ARCHITECTURE.md` and injects it into every agent's context
|
|
@@ -63,16 +63,16 @@ GROOVE auto-detects monorepo workspaces (npm, pnpm, lerna) and lets you spawn ea
|
|
|
63
63
|
|
|
64
64
|
## Remote Access
|
|
65
65
|
|
|
66
|
-
Run
|
|
66
|
+
Run groove on a VPS and manage your agents from anywhere. No ports exposed to the internet. No tokens. No custom auth code. Zero attack surface.
|
|
67
67
|
|
|
68
68
|
### How It Works
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
groove never opens ports to the public internet. Instead, it uses battle-tested transport layers — SSH tunnels and WireGuard (Tailscale) — to keep your daemon private.
|
|
71
71
|
|
|
72
72
|
```
|
|
73
73
|
Your laptop Your VPS
|
|
74
74
|
┌──────────┐ SSH tunnel ┌──────────────────┐
|
|
75
|
-
│ Browser │ ◄────────────────► │
|
|
75
|
+
│ Browser │ ◄────────────────► │ groove daemon │
|
|
76
76
|
│ localhost│ encrypted │ 127.0.0.1:31415 │
|
|
77
77
|
└──────────┘ └──────────────────┘
|
|
78
78
|
Zero open ports
|
|
@@ -99,7 +99,7 @@ groove disconnect # close when done
|
|
|
99
99
|
|
|
100
100
|
That's it. The GUI opens in your browser automatically.
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
groove auto-detects your environment — VS Code Remote, plain SSH, or local — and tells you exactly what to do. SSH config aliases work too: `groove connect my-vps`.
|
|
103
103
|
|
|
104
104
|
### Tailscale / LAN Access
|
|
105
105
|
|
|
@@ -114,7 +114,7 @@ Open `http://<ip>:31415` from any device on the same network. Tailscale handles
|
|
|
114
114
|
|
|
115
115
|
### What's Blocked
|
|
116
116
|
|
|
117
|
-
|
|
117
|
+
groove will reject any attempt to expose the daemon directly to the internet:
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
groove start --host 0.0.0.0 # REJECTED — not allowed
|
|
@@ -124,7 +124,7 @@ This is by design. Direct exposure requires custom auth, rate limiting, TLS mana
|
|
|
124
124
|
|
|
125
125
|
### Federation (Preview)
|
|
126
126
|
|
|
127
|
-
Pair
|
|
127
|
+
Pair groove daemons across machines with Ed25519 key exchange. The security layer is built — cross-server agent coordination (typed contracts, federated registry) is coming soon.
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
130
|
groove federation pair 100.64.1.5 # pair two daemons
|
|
@@ -137,7 +137,7 @@ Every cross-server message is signed with Ed25519 keys generated during a pairin
|
|
|
137
137
|
```
|
|
138
138
|
Server A Server B
|
|
139
139
|
┌──────────────┐ signed contract ┌──────────────┐
|
|
140
|
-
│
|
|
140
|
+
│ groove daemon│ ◄────────────────►│ groove daemon│
|
|
141
141
|
│ Ed25519 key │ verify + audit │ Ed25519 key │
|
|
142
142
|
└──────────────┘ └──────────────┘
|
|
143
143
|
```
|
|
@@ -176,7 +176,7 @@ Append-only, `0600` permissions, auto-rotates at 5MB. When team auth is added, e
|
|
|
176
176
|
|
|
177
177
|
**What we explicitly don't defend against:** Compromised SSH keys, root access to VPS, malicious AI provider responses (out of scope — we're a process manager).
|
|
178
178
|
|
|
179
|
-
**The principle:** "There's nothing to attack" is better than "we have a security system and here's why it's good."
|
|
179
|
+
**The principle:** "There's nothing to attack" is better than "we have a security system and here's why it's good." groove has zero auth code. The transport layer does all the work.
|
|
180
180
|
|
|
181
181
|
---
|
|
182
182
|
|
|
@@ -189,7 +189,7 @@ Append-only, `0600` permissions, auto-rotates at 5MB. When team auth is added, e
|
|
|
189
189
|
| **Gemini CLI** | API Key | 3.1 Pro, 3 Flash, 3.1 Flash Lite, 2.5 Pro, 2.5 Flash |
|
|
190
190
|
| **Ollama** | Local | Any |
|
|
191
191
|
|
|
192
|
-
|
|
192
|
+
groove is a process manager — it spawns actual AI tool binaries. It never proxies API calls, never touches OAuth tokens, never impersonates any client. Your AI tools talk directly to their servers.
|
|
193
193
|
|
|
194
194
|
Works in any terminal, any IDE, any OS. Technical and non-technical users alike.
|
|
195
195
|
|
|
@@ -198,15 +198,17 @@ Works in any terminal, any IDE, any OS. Technical and non-technical users alike.
|
|
|
198
198
|
Open the dashboard after starting the daemon (local or remote):
|
|
199
199
|
|
|
200
200
|
- **Agent Tree** — visual node graph with Bezier spline connections, role badges, live status
|
|
201
|
+
- **File Editor** — CodeMirror 6 with syntax highlighting, file tree, tabs, media viewer, and embedded terminal
|
|
201
202
|
- **Chat** — instruct agents, query without disrupting, continue completed agents, streaming text
|
|
202
203
|
- **Command Center** — gauge charts, live telemetry, token savings, model routing, adaptive thresholds
|
|
203
204
|
- **Quick Launch** — planner recommends team, one-click to spawn all
|
|
205
|
+
- **Skills Store** — app-store marketplace for agent skills with ratings and verification
|
|
204
206
|
- **PM Review Log** — full audit trail of AI Project Manager decisions
|
|
205
207
|
- **Team Management** — save, load, export, import agent configurations
|
|
206
208
|
|
|
207
209
|
## Adaptive Model Routing
|
|
208
210
|
|
|
209
|
-
|
|
211
|
+
groove routes tasks to the cheapest model that can handle them. Planners get Opus (deep reasoning). Backends get Sonnet (balanced). Docs get Haiku (fast and cheap). The classifier learns from agent activity and adjusts over time.
|
|
210
212
|
|
|
211
213
|
| Tier | Cost | Used For |
|
|
212
214
|
|------|------|----------|
|
|
@@ -218,7 +220,7 @@ GROOVE routes tasks to the cheapest model that can handle them. Planners get Opu
|
|
|
218
220
|
|
|
219
221
|
```
|
|
220
222
|
┌──────────────────────────────────────────────┐
|
|
221
|
-
│
|
|
223
|
+
│ groove DAEMON (:31415) │
|
|
222
224
|
│ │
|
|
223
225
|
│ Registry · Introducer · Lock Manager │
|
|
224
226
|
│ Journalist · Rotator · Adaptive · Indexer │
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "slack",
|
|
4
|
+
"name": "Slack",
|
|
5
|
+
"description": "Send and read messages, manage channels, search history, post reactions and thread replies",
|
|
6
|
+
"category": "communication",
|
|
7
|
+
"icon": "slack",
|
|
8
|
+
"tags": ["chat", "messaging", "notifications", "team"],
|
|
9
|
+
"roles": ["cmo", "ea", "support", "fullstack"],
|
|
10
|
+
"npmPackage": "@modelcontextprotocol/server-slack",
|
|
11
|
+
"transport": "stdio",
|
|
12
|
+
"command": "npx",
|
|
13
|
+
"args": ["-y", "@modelcontextprotocol/server-slack"],
|
|
14
|
+
"envKeys": [
|
|
15
|
+
{ "key": "SLACK_BOT_TOKEN", "label": "Bot Token", "placeholder": "xoxb-...", "required": true },
|
|
16
|
+
{ "key": "SLACK_TEAM_ID", "label": "Team ID", "placeholder": "T01234567", "required": true }
|
|
17
|
+
],
|
|
18
|
+
"featured": true,
|
|
19
|
+
"downloads": 0,
|
|
20
|
+
"rating": 0,
|
|
21
|
+
"ratingCount": 0,
|
|
22
|
+
"verified": "mcp-official"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "github",
|
|
26
|
+
"name": "GitHub",
|
|
27
|
+
"description": "Manage repos, issues, pull requests, code search, file operations, and workflows",
|
|
28
|
+
"category": "developer",
|
|
29
|
+
"icon": "github",
|
|
30
|
+
"tags": ["git", "repos", "issues", "pull-requests", "ci"],
|
|
31
|
+
"roles": ["backend", "frontend", "fullstack", "devops"],
|
|
32
|
+
"npmPackage": "@modelcontextprotocol/server-github",
|
|
33
|
+
"transport": "stdio",
|
|
34
|
+
"command": "npx",
|
|
35
|
+
"args": ["-y", "@modelcontextprotocol/server-github"],
|
|
36
|
+
"envKeys": [
|
|
37
|
+
{ "key": "GITHUB_PERSONAL_ACCESS_TOKEN", "label": "Personal Access Token", "placeholder": "ghp_...", "required": true }
|
|
38
|
+
],
|
|
39
|
+
"featured": true,
|
|
40
|
+
"downloads": 0,
|
|
41
|
+
"rating": 0,
|
|
42
|
+
"ratingCount": 0,
|
|
43
|
+
"verified": "mcp-official"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"id": "stripe",
|
|
47
|
+
"name": "Stripe",
|
|
48
|
+
"description": "Manage customers, payments, subscriptions, invoices, and financial data",
|
|
49
|
+
"category": "finance",
|
|
50
|
+
"icon": "stripe",
|
|
51
|
+
"tags": ["payments", "billing", "subscriptions", "finance"],
|
|
52
|
+
"roles": ["cfo", "analyst", "fullstack"],
|
|
53
|
+
"npmPackage": "@stripe/agent-toolkit",
|
|
54
|
+
"transport": "stdio",
|
|
55
|
+
"command": "npx",
|
|
56
|
+
"args": ["-y", "@stripe/agent-toolkit", "mcp"],
|
|
57
|
+
"envKeys": [
|
|
58
|
+
{ "key": "STRIPE_SECRET_KEY", "label": "Secret Key", "placeholder": "sk_...", "required": true }
|
|
59
|
+
],
|
|
60
|
+
"featured": true,
|
|
61
|
+
"downloads": 0,
|
|
62
|
+
"rating": 0,
|
|
63
|
+
"ratingCount": 0,
|
|
64
|
+
"verified": "verified"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"id": "google-calendar",
|
|
68
|
+
"name": "Google Calendar",
|
|
69
|
+
"description": "Create, list, and update calendar events, check availability, manage schedules",
|
|
70
|
+
"category": "productivity",
|
|
71
|
+
"icon": "calendar",
|
|
72
|
+
"tags": ["calendar", "scheduling", "events", "meetings"],
|
|
73
|
+
"roles": ["ea", "cmo"],
|
|
74
|
+
"npmPackage": "@anthropic-ai/mcp-server-google-calendar",
|
|
75
|
+
"transport": "stdio",
|
|
76
|
+
"command": "npx",
|
|
77
|
+
"args": ["-y", "@anthropic-ai/mcp-server-google-calendar"],
|
|
78
|
+
"envKeys": [
|
|
79
|
+
{ "key": "GOOGLE_CLIENT_ID", "label": "OAuth Client ID", "required": true },
|
|
80
|
+
{ "key": "GOOGLE_CLIENT_SECRET", "label": "OAuth Client Secret", "required": true },
|
|
81
|
+
{ "key": "GOOGLE_REFRESH_TOKEN", "label": "Refresh Token", "required": true }
|
|
82
|
+
],
|
|
83
|
+
"featured": false,
|
|
84
|
+
"downloads": 0,
|
|
85
|
+
"rating": 0,
|
|
86
|
+
"ratingCount": 0,
|
|
87
|
+
"verified": "community"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "gmail",
|
|
91
|
+
"name": "Gmail",
|
|
92
|
+
"description": "Send, read, search, and draft emails via Gmail",
|
|
93
|
+
"category": "communication",
|
|
94
|
+
"icon": "email",
|
|
95
|
+
"tags": ["email", "inbox", "messaging", "notifications"],
|
|
96
|
+
"roles": ["ea", "cmo", "support"],
|
|
97
|
+
"npmPackage": "@anthropic-ai/mcp-server-gmail",
|
|
98
|
+
"transport": "stdio",
|
|
99
|
+
"command": "npx",
|
|
100
|
+
"args": ["-y", "@anthropic-ai/mcp-server-gmail"],
|
|
101
|
+
"envKeys": [
|
|
102
|
+
{ "key": "GOOGLE_CLIENT_ID", "label": "OAuth Client ID", "required": true },
|
|
103
|
+
{ "key": "GOOGLE_CLIENT_SECRET", "label": "OAuth Client Secret", "required": true },
|
|
104
|
+
{ "key": "GOOGLE_REFRESH_TOKEN", "label": "Refresh Token", "required": true }
|
|
105
|
+
],
|
|
106
|
+
"featured": false,
|
|
107
|
+
"downloads": 0,
|
|
108
|
+
"rating": 0,
|
|
109
|
+
"ratingCount": 0,
|
|
110
|
+
"verified": "community"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"id": "postgres",
|
|
114
|
+
"name": "PostgreSQL",
|
|
115
|
+
"description": "Query databases, inspect schemas, run SQL, and analyze data",
|
|
116
|
+
"category": "database",
|
|
117
|
+
"icon": "database",
|
|
118
|
+
"tags": ["sql", "database", "queries", "analytics"],
|
|
119
|
+
"roles": ["analyst", "backend", "cfo"],
|
|
120
|
+
"npmPackage": "@modelcontextprotocol/server-postgres",
|
|
121
|
+
"transport": "stdio",
|
|
122
|
+
"command": "npx",
|
|
123
|
+
"args": ["-y", "@modelcontextprotocol/server-postgres"],
|
|
124
|
+
"envKeys": [
|
|
125
|
+
{ "key": "POSTGRES_CONNECTION_STRING", "label": "Connection String", "placeholder": "postgresql://user:pass@host:5432/db", "required": true }
|
|
126
|
+
],
|
|
127
|
+
"featured": false,
|
|
128
|
+
"downloads": 0,
|
|
129
|
+
"rating": 0,
|
|
130
|
+
"ratingCount": 0,
|
|
131
|
+
"verified": "mcp-official"
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"id": "brave-search",
|
|
135
|
+
"name": "Brave Search",
|
|
136
|
+
"description": "Web search and local search via Brave Search API",
|
|
137
|
+
"category": "analytics",
|
|
138
|
+
"icon": "search",
|
|
139
|
+
"tags": ["search", "web", "research", "data"],
|
|
140
|
+
"roles": ["cmo", "analyst", "planner"],
|
|
141
|
+
"npmPackage": "@modelcontextprotocol/server-brave-search",
|
|
142
|
+
"transport": "stdio",
|
|
143
|
+
"command": "npx",
|
|
144
|
+
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
|
|
145
|
+
"envKeys": [
|
|
146
|
+
{ "key": "BRAVE_API_KEY", "label": "API Key", "placeholder": "BSA...", "required": true }
|
|
147
|
+
],
|
|
148
|
+
"featured": false,
|
|
149
|
+
"downloads": 0,
|
|
150
|
+
"rating": 0,
|
|
151
|
+
"ratingCount": 0,
|
|
152
|
+
"verified": "mcp-official"
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
"id": "google-drive",
|
|
156
|
+
"name": "Google Drive",
|
|
157
|
+
"description": "Search, read, and manage files in Google Drive",
|
|
158
|
+
"category": "productivity",
|
|
159
|
+
"icon": "drive",
|
|
160
|
+
"tags": ["files", "documents", "sheets", "storage"],
|
|
161
|
+
"roles": ["ea", "analyst", "cmo"],
|
|
162
|
+
"npmPackage": "@modelcontextprotocol/server-gdrive",
|
|
163
|
+
"transport": "stdio",
|
|
164
|
+
"command": "npx",
|
|
165
|
+
"args": ["-y", "@modelcontextprotocol/server-gdrive"],
|
|
166
|
+
"envKeys": [
|
|
167
|
+
{ "key": "GOOGLE_CLIENT_ID", "label": "OAuth Client ID", "required": true },
|
|
168
|
+
{ "key": "GOOGLE_CLIENT_SECRET", "label": "OAuth Client Secret", "required": true },
|
|
169
|
+
{ "key": "GOOGLE_REFRESH_TOKEN", "label": "Refresh Token", "required": true }
|
|
170
|
+
],
|
|
171
|
+
"featured": false,
|
|
172
|
+
"downloads": 0,
|
|
173
|
+
"rating": 0,
|
|
174
|
+
"ratingCount": 0,
|
|
175
|
+
"verified": "mcp-official"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"id": "linear",
|
|
179
|
+
"name": "Linear",
|
|
180
|
+
"description": "Create and manage issues, projects, and sprints in Linear",
|
|
181
|
+
"category": "productivity",
|
|
182
|
+
"icon": "linear",
|
|
183
|
+
"tags": ["issues", "project-management", "tickets", "sprints"],
|
|
184
|
+
"roles": ["fullstack", "backend", "devops"],
|
|
185
|
+
"npmPackage": "@ibraheem4/linear-mcp-server",
|
|
186
|
+
"transport": "stdio",
|
|
187
|
+
"command": "npx",
|
|
188
|
+
"args": ["-y", "@ibraheem4/linear-mcp-server"],
|
|
189
|
+
"envKeys": [
|
|
190
|
+
{ "key": "LINEAR_API_KEY", "label": "API Key", "required": true }
|
|
191
|
+
],
|
|
192
|
+
"featured": false,
|
|
193
|
+
"downloads": 0,
|
|
194
|
+
"rating": 0,
|
|
195
|
+
"ratingCount": 0,
|
|
196
|
+
"verified": "community"
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"id": "notion",
|
|
200
|
+
"name": "Notion",
|
|
201
|
+
"description": "Read, create, and update Notion pages and databases",
|
|
202
|
+
"category": "productivity",
|
|
203
|
+
"icon": "notion",
|
|
204
|
+
"tags": ["wiki", "docs", "notes", "databases"],
|
|
205
|
+
"roles": ["ea", "cmo", "analyst"],
|
|
206
|
+
"npmPackage": "@notionhq/notion-mcp-server",
|
|
207
|
+
"transport": "stdio",
|
|
208
|
+
"command": "npx",
|
|
209
|
+
"args": ["-y", "@notionhq/notion-mcp-server"],
|
|
210
|
+
"envKeys": [
|
|
211
|
+
{ "key": "NOTION_API_KEY", "label": "Integration Token", "placeholder": "ntn_...", "required": true }
|
|
212
|
+
],
|
|
213
|
+
"featured": false,
|
|
214
|
+
"downloads": 0,
|
|
215
|
+
"rating": 0,
|
|
216
|
+
"ratingCount": 0,
|
|
217
|
+
"verified": "community"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"id": "discord",
|
|
221
|
+
"name": "Discord",
|
|
222
|
+
"description": "Send and read messages, manage channels and servers on Discord",
|
|
223
|
+
"category": "communication",
|
|
224
|
+
"icon": "discord",
|
|
225
|
+
"tags": ["chat", "community", "messaging", "voice"],
|
|
226
|
+
"roles": ["cmo", "support"],
|
|
227
|
+
"npmPackage": "mcp-discord",
|
|
228
|
+
"transport": "stdio",
|
|
229
|
+
"command": "npx",
|
|
230
|
+
"args": ["-y", "mcp-discord"],
|
|
231
|
+
"envKeys": [
|
|
232
|
+
{ "key": "DISCORD_BOT_TOKEN", "label": "Bot Token", "required": true }
|
|
233
|
+
],
|
|
234
|
+
"featured": false,
|
|
235
|
+
"downloads": 0,
|
|
236
|
+
"rating": 0,
|
|
237
|
+
"ratingCount": 0,
|
|
238
|
+
"verified": "community"
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"id": "home-assistant",
|
|
242
|
+
"name": "Home Assistant",
|
|
243
|
+
"description": "Control smart home devices, query states, and manage automations",
|
|
244
|
+
"category": "smart-home",
|
|
245
|
+
"icon": "home",
|
|
246
|
+
"tags": ["iot", "smart-home", "automation", "devices"],
|
|
247
|
+
"roles": ["home"],
|
|
248
|
+
"npmPackage": "mcp-home-assistant",
|
|
249
|
+
"transport": "stdio",
|
|
250
|
+
"command": "npx",
|
|
251
|
+
"args": ["-y", "mcp-home-assistant"],
|
|
252
|
+
"envKeys": [
|
|
253
|
+
{ "key": "HOME_ASSISTANT_URL", "label": "HA URL", "placeholder": "http://homeassistant.local:8123", "required": true },
|
|
254
|
+
{ "key": "HOME_ASSISTANT_TOKEN", "label": "Long-Lived Access Token", "required": true }
|
|
255
|
+
],
|
|
256
|
+
"featured": false,
|
|
257
|
+
"downloads": 0,
|
|
258
|
+
"rating": 0,
|
|
259
|
+
"ratingCount": 0,
|
|
260
|
+
"verified": "community"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"id": "filesystem",
|
|
264
|
+
"name": "Filesystem",
|
|
265
|
+
"description": "Read, write, search, and manage files on the local filesystem",
|
|
266
|
+
"category": "developer",
|
|
267
|
+
"icon": "folder",
|
|
268
|
+
"tags": ["files", "filesystem", "local", "storage"],
|
|
269
|
+
"roles": ["backend", "fullstack", "devops"],
|
|
270
|
+
"npmPackage": "@modelcontextprotocol/server-filesystem",
|
|
271
|
+
"transport": "stdio",
|
|
272
|
+
"command": "npx",
|
|
273
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem"],
|
|
274
|
+
"envKeys": [],
|
|
275
|
+
"featured": false,
|
|
276
|
+
"downloads": 0,
|
|
277
|
+
"rating": 0,
|
|
278
|
+
"ratingCount": 0,
|
|
279
|
+
"verified": "mcp-official"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"id": "google-maps",
|
|
283
|
+
"name": "Google Maps",
|
|
284
|
+
"description": "Geocoding, directions, place search, and distance calculations",
|
|
285
|
+
"category": "analytics",
|
|
286
|
+
"icon": "map",
|
|
287
|
+
"tags": ["maps", "location", "directions", "places"],
|
|
288
|
+
"roles": ["analyst", "ea"],
|
|
289
|
+
"npmPackage": "@modelcontextprotocol/server-google-maps",
|
|
290
|
+
"transport": "stdio",
|
|
291
|
+
"command": "npx",
|
|
292
|
+
"args": ["-y", "@modelcontextprotocol/server-google-maps"],
|
|
293
|
+
"envKeys": [
|
|
294
|
+
{ "key": "GOOGLE_MAPS_API_KEY", "label": "API Key", "required": true }
|
|
295
|
+
],
|
|
296
|
+
"featured": false,
|
|
297
|
+
"downloads": 0,
|
|
298
|
+
"rating": 0,
|
|
299
|
+
"ratingCount": 0,
|
|
300
|
+
"verified": "mcp-official"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"id": "sqlite",
|
|
304
|
+
"name": "SQLite",
|
|
305
|
+
"description": "Query and manage SQLite databases, inspect schemas, run SQL",
|
|
306
|
+
"category": "database",
|
|
307
|
+
"icon": "database",
|
|
308
|
+
"tags": ["sql", "database", "local", "lightweight"],
|
|
309
|
+
"roles": ["analyst", "backend"],
|
|
310
|
+
"npmPackage": "@modelcontextprotocol/server-sqlite",
|
|
311
|
+
"transport": "stdio",
|
|
312
|
+
"command": "npx",
|
|
313
|
+
"args": ["-y", "@modelcontextprotocol/server-sqlite"],
|
|
314
|
+
"envKeys": [],
|
|
315
|
+
"featured": false,
|
|
316
|
+
"downloads": 0,
|
|
317
|
+
"rating": 0,
|
|
318
|
+
"ratingCount": 0,
|
|
319
|
+
"verified": "mcp-official"
|
|
320
|
+
}
|
|
321
|
+
]
|
|
@@ -444,6 +444,158 @@ export function createApi(app, daemon) {
|
|
|
444
444
|
res.json({ id: agent.id, skills });
|
|
445
445
|
});
|
|
446
446
|
|
|
447
|
+
// --- Integrations ---
|
|
448
|
+
|
|
449
|
+
app.get('/api/integrations/registry', async (req, res) => {
|
|
450
|
+
const integrations = await daemon.integrations.getRegistry({
|
|
451
|
+
search: req.query.search || '',
|
|
452
|
+
category: req.query.category || 'all',
|
|
453
|
+
});
|
|
454
|
+
res.json({
|
|
455
|
+
integrations,
|
|
456
|
+
categories: daemon.integrations.getCategories(),
|
|
457
|
+
});
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
app.get('/api/integrations/installed', (req, res) => {
|
|
461
|
+
res.json(daemon.integrations.getInstalled());
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
app.post('/api/integrations/:id/install', async (req, res) => {
|
|
465
|
+
try {
|
|
466
|
+
const result = await daemon.integrations.install(req.params.id);
|
|
467
|
+
res.json(result);
|
|
468
|
+
} catch (err) {
|
|
469
|
+
res.status(400).json({ error: err.message });
|
|
470
|
+
}
|
|
471
|
+
});
|
|
472
|
+
|
|
473
|
+
app.delete('/api/integrations/:id', async (req, res) => {
|
|
474
|
+
try {
|
|
475
|
+
const result = await daemon.integrations.uninstall(req.params.id);
|
|
476
|
+
res.json(result);
|
|
477
|
+
} catch (err) {
|
|
478
|
+
res.status(400).json({ error: err.message });
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
app.get('/api/integrations/:id/status', (req, res) => {
|
|
483
|
+
const status = daemon.integrations.getStatus(req.params.id);
|
|
484
|
+
if (!status) return res.status(404).json({ error: 'Integration not found' });
|
|
485
|
+
res.json(status);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
app.post('/api/integrations/:id/credentials', (req, res) => {
|
|
489
|
+
try {
|
|
490
|
+
const { key, value } = req.body || {};
|
|
491
|
+
if (!key || !value) return res.status(400).json({ error: 'key and value are required' });
|
|
492
|
+
daemon.integrations.setCredential(req.params.id, key, value);
|
|
493
|
+
res.json({ ok: true });
|
|
494
|
+
} catch (err) {
|
|
495
|
+
res.status(400).json({ error: err.message });
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
app.delete('/api/integrations/:id/credentials/:key', (req, res) => {
|
|
500
|
+
try {
|
|
501
|
+
daemon.integrations.deleteCredential(req.params.id, req.params.key);
|
|
502
|
+
res.json({ ok: true });
|
|
503
|
+
} catch (err) {
|
|
504
|
+
res.status(400).json({ error: err.message });
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// --- Agent Integrations (attach/detach) ---
|
|
509
|
+
|
|
510
|
+
app.post('/api/agents/:agentId/integrations/:integrationId', (req, res) => {
|
|
511
|
+
const agent = daemon.registry.get(req.params.agentId);
|
|
512
|
+
if (!agent) return res.status(404).json({ error: 'Agent not found' });
|
|
513
|
+
const integrationId = req.params.integrationId;
|
|
514
|
+
if (!daemon.integrations._isInstalled(integrationId)) {
|
|
515
|
+
return res.status(400).json({ error: 'Integration not installed. Install it first.' });
|
|
516
|
+
}
|
|
517
|
+
const integrations = agent.integrations || [];
|
|
518
|
+
if (integrations.includes(integrationId)) {
|
|
519
|
+
return res.json({ id: agent.id, integrations });
|
|
520
|
+
}
|
|
521
|
+
daemon.registry.update(agent.id, { integrations: [...integrations, integrationId] });
|
|
522
|
+
daemon.audit.log('integration.attach', { agentId: agent.id, integrationId });
|
|
523
|
+
res.json({ id: agent.id, integrations: [...integrations, integrationId] });
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
app.delete('/api/agents/:agentId/integrations/:integrationId', (req, res) => {
|
|
527
|
+
const agent = daemon.registry.get(req.params.agentId);
|
|
528
|
+
if (!agent) return res.status(404).json({ error: 'Agent not found' });
|
|
529
|
+
const integrations = (agent.integrations || []).filter((s) => s !== req.params.integrationId);
|
|
530
|
+
daemon.registry.update(agent.id, { integrations });
|
|
531
|
+
daemon.audit.log('integration.detach', { agentId: agent.id, integrationId: req.params.integrationId });
|
|
532
|
+
res.json({ id: agent.id, integrations });
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// --- Schedules ---
|
|
536
|
+
|
|
537
|
+
app.get('/api/schedules', (req, res) => {
|
|
538
|
+
res.json(daemon.scheduler.list());
|
|
539
|
+
});
|
|
540
|
+
|
|
541
|
+
app.post('/api/schedules', (req, res) => {
|
|
542
|
+
try {
|
|
543
|
+
const schedule = daemon.scheduler.create(req.body);
|
|
544
|
+
res.status(201).json(schedule);
|
|
545
|
+
} catch (err) {
|
|
546
|
+
res.status(400).json({ error: err.message });
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
app.get('/api/schedules/:id', (req, res) => {
|
|
551
|
+
const schedule = daemon.scheduler.get(req.params.id);
|
|
552
|
+
if (!schedule) return res.status(404).json({ error: 'Schedule not found' });
|
|
553
|
+
res.json(schedule);
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
app.patch('/api/schedules/:id', (req, res) => {
|
|
557
|
+
try {
|
|
558
|
+
const schedule = daemon.scheduler.update(req.params.id, req.body);
|
|
559
|
+
res.json(schedule);
|
|
560
|
+
} catch (err) {
|
|
561
|
+
res.status(400).json({ error: err.message });
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
app.delete('/api/schedules/:id', (req, res) => {
|
|
566
|
+
try {
|
|
567
|
+
daemon.scheduler.delete(req.params.id);
|
|
568
|
+
res.json({ ok: true });
|
|
569
|
+
} catch (err) {
|
|
570
|
+
res.status(400).json({ error: err.message });
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
app.post('/api/schedules/:id/enable', (req, res) => {
|
|
575
|
+
try {
|
|
576
|
+
res.json(daemon.scheduler.enable(req.params.id));
|
|
577
|
+
} catch (err) {
|
|
578
|
+
res.status(400).json({ error: err.message });
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
|
|
582
|
+
app.post('/api/schedules/:id/disable', (req, res) => {
|
|
583
|
+
try {
|
|
584
|
+
res.json(daemon.scheduler.disable(req.params.id));
|
|
585
|
+
} catch (err) {
|
|
586
|
+
res.status(400).json({ error: err.message });
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
app.post('/api/schedules/:id/run', async (req, res) => {
|
|
591
|
+
try {
|
|
592
|
+
const agent = await daemon.scheduler.run(req.params.id);
|
|
593
|
+
res.json({ ok: true, agentId: agent.id });
|
|
594
|
+
} catch (err) {
|
|
595
|
+
res.status(400).json({ error: err.message });
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
|
|
447
599
|
// --- Directory Browser ---
|
|
448
600
|
|
|
449
601
|
app.get('/api/browse', (req, res) => {
|