groove-dev 0.12.8 → 0.13.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.
@@ -0,0 +1,233 @@
1
+ [
2
+ {
3
+ "id": "frontend-design",
4
+ "name": "Frontend Design",
5
+ "description": "Create distinctive, production-grade frontend interfaces with high design quality. Avoids generic AI aesthetics.",
6
+ "author": "Anthropic",
7
+ "category": "design",
8
+ "tags": ["frontend", "ui", "css", "react", "design-system"],
9
+ "roles": ["frontend", "fullstack"],
10
+ "source": "claude-official",
11
+ "icon": "P"
12
+ },
13
+ {
14
+ "id": "code-review",
15
+ "name": "Code Review",
16
+ "description": "Comprehensive PR code review using parallel specialized agents. Checks CLAUDE.md compliance, bugs, git history, and previous PR comments.",
17
+ "author": "Anthropic",
18
+ "category": "quality",
19
+ "tags": ["review", "pr", "github", "quality"],
20
+ "roles": ["testing", "fullstack"],
21
+ "source": "claude-official",
22
+ "icon": "R"
23
+ },
24
+ {
25
+ "id": "security-guidance",
26
+ "name": "Security Guidance",
27
+ "description": "Security-focused development guidance. OWASP top 10, input validation, auth patterns, secrets management.",
28
+ "author": "Anthropic",
29
+ "category": "security",
30
+ "tags": ["security", "owasp", "auth", "validation"],
31
+ "roles": ["backend", "fullstack", "devops"],
32
+ "source": "claude-official",
33
+ "icon": "S"
34
+ },
35
+ {
36
+ "id": "claude-automation-recommender",
37
+ "name": "Automation Recommender",
38
+ "description": "Analyze a codebase and recommend Claude Code automations — hooks, subagents, skills, plugins, MCP servers.",
39
+ "author": "Anthropic",
40
+ "category": "devtools",
41
+ "tags": ["automation", "hooks", "plugins", "mcp", "setup"],
42
+ "roles": ["planner", "devops", "fullstack"],
43
+ "source": "claude-official",
44
+ "icon": "A"
45
+ },
46
+ {
47
+ "id": "claude-md-improver",
48
+ "name": "CLAUDE.md Improver",
49
+ "description": "Audit and improve CLAUDE.md files. Scans quality, evaluates against templates, makes targeted updates.",
50
+ "author": "Anthropic",
51
+ "category": "devtools",
52
+ "tags": ["claude-md", "project-config", "audit"],
53
+ "roles": ["planner", "fullstack"],
54
+ "source": "claude-official",
55
+ "icon": "C"
56
+ },
57
+ {
58
+ "id": "build-mcp-server",
59
+ "name": "Build MCP Server",
60
+ "description": "End-to-end MCP server development. Interrogates use case, picks deployment model, designs tools, hands off to specialized skills.",
61
+ "author": "Anthropic",
62
+ "category": "devtools",
63
+ "tags": ["mcp", "api", "integration", "tools"],
64
+ "roles": ["backend", "fullstack"],
65
+ "source": "claude-official",
66
+ "icon": "M"
67
+ },
68
+ {
69
+ "id": "build-mcp-app",
70
+ "name": "Build MCP App",
71
+ "description": "Add interactive UI widgets to MCP servers — forms, pickers, dashboards, confirmation dialogs inline in chat.",
72
+ "author": "Anthropic",
73
+ "category": "devtools",
74
+ "tags": ["mcp", "ui", "widgets", "apps-sdk"],
75
+ "roles": ["frontend", "fullstack"],
76
+ "source": "claude-official",
77
+ "icon": "U"
78
+ },
79
+ {
80
+ "id": "feature-dev",
81
+ "name": "Feature Development",
82
+ "description": "Guided feature development with codebase understanding and architecture focus. Structured workflow from research to implementation.",
83
+ "author": "Anthropic",
84
+ "category": "workflow",
85
+ "tags": ["feature", "architecture", "guided", "development"],
86
+ "roles": ["backend", "frontend", "fullstack"],
87
+ "source": "claude-official",
88
+ "icon": "F"
89
+ },
90
+ {
91
+ "id": "skill-creator",
92
+ "name": "Skill Creator",
93
+ "description": "Create new skills, modify existing ones, run evals, benchmark performance. The meta-skill for building skills.",
94
+ "author": "Anthropic",
95
+ "category": "devtools",
96
+ "tags": ["skills", "plugins", "meta", "evals"],
97
+ "roles": ["planner", "fullstack"],
98
+ "source": "claude-official",
99
+ "icon": "K"
100
+ },
101
+ {
102
+ "id": "plugin-structure",
103
+ "name": "Plugin Structure",
104
+ "description": "Scaffold and organize Claude Code plugins. Directory layout, manifest, components, auto-discovery patterns.",
105
+ "author": "Anthropic",
106
+ "category": "devtools",
107
+ "tags": ["plugins", "scaffold", "architecture"],
108
+ "roles": ["fullstack", "devops"],
109
+ "source": "claude-official",
110
+ "icon": "L"
111
+ },
112
+ {
113
+ "id": "hook-development",
114
+ "name": "Hook Development",
115
+ "description": "Create PreToolUse, PostToolUse, Stop hooks. Event-driven automation, tool validation, prompt-based hooks API.",
116
+ "author": "Anthropic",
117
+ "category": "devtools",
118
+ "tags": ["hooks", "automation", "events", "validation"],
119
+ "roles": ["devops", "fullstack"],
120
+ "source": "claude-official",
121
+ "icon": "H"
122
+ },
123
+ {
124
+ "id": "agent-development",
125
+ "name": "Agent Development",
126
+ "description": "Create subagents with system prompts, triggering conditions, tool access, and autonomous behavior patterns.",
127
+ "author": "Anthropic",
128
+ "category": "devtools",
129
+ "tags": ["agents", "subagents", "autonomous"],
130
+ "roles": ["planner", "fullstack"],
131
+ "source": "claude-official",
132
+ "icon": "G"
133
+ },
134
+ {
135
+ "id": "playground",
136
+ "name": "Playground Builder",
137
+ "description": "Create interactive HTML playgrounds — single-file explorers with live preview, visual controls, and copy-out prompts.",
138
+ "author": "Anthropic",
139
+ "category": "design",
140
+ "tags": ["playground", "interactive", "html", "demo"],
141
+ "roles": ["frontend", "docs"],
142
+ "source": "claude-official",
143
+ "icon": "Y"
144
+ },
145
+ {
146
+ "id": "math-olympiad",
147
+ "name": "Math Olympiad",
148
+ "description": "Advanced mathematical problem solving. Competition-level math, proofs, and formal reasoning.",
149
+ "author": "Anthropic",
150
+ "category": "specialized",
151
+ "tags": ["math", "proofs", "reasoning", "competition"],
152
+ "roles": [],
153
+ "source": "claude-official",
154
+ "icon": "X"
155
+ },
156
+ {
157
+ "id": "hookify",
158
+ "name": "Hookify",
159
+ "description": "Create hooks to prevent unwanted behaviors from conversation analysis or explicit instructions. Rule-based automation.",
160
+ "author": "Anthropic",
161
+ "category": "devtools",
162
+ "tags": ["hooks", "rules", "automation", "guardrails"],
163
+ "roles": ["devops", "fullstack"],
164
+ "source": "claude-official",
165
+ "icon": "I"
166
+ },
167
+ {
168
+ "id": "code-simplifier",
169
+ "name": "Code Simplifier",
170
+ "description": "Review changed code for reuse, quality, and efficiency. Identifies over-engineering and suggests simplifications.",
171
+ "author": "Anthropic",
172
+ "category": "quality",
173
+ "tags": ["refactor", "simplify", "quality", "efficiency"],
174
+ "roles": ["backend", "frontend", "fullstack"],
175
+ "source": "claude-official",
176
+ "icon": "Z"
177
+ },
178
+ {
179
+ "id": "commit-commands",
180
+ "name": "Commit Commands",
181
+ "description": "Git workflow commands — commit, push, open PR, clean gone branches. Structured commit messages.",
182
+ "author": "Anthropic",
183
+ "category": "workflow",
184
+ "tags": ["git", "commit", "pr", "workflow"],
185
+ "roles": ["fullstack", "backend", "frontend"],
186
+ "source": "claude-official",
187
+ "icon": "V"
188
+ },
189
+ {
190
+ "id": "pr-review-toolkit",
191
+ "name": "PR Review Toolkit",
192
+ "description": "Comprehensive PR review using specialized parallel agents. Multi-angle analysis with confidence scoring.",
193
+ "author": "Anthropic",
194
+ "category": "quality",
195
+ "tags": ["pr", "review", "github", "parallel-agents"],
196
+ "roles": ["testing", "fullstack"],
197
+ "source": "claude-official",
198
+ "icon": "T"
199
+ },
200
+ {
201
+ "id": "new-sdk-app",
202
+ "name": "Agent SDK Starter",
203
+ "description": "Create and setup a new Claude Agent SDK application. Scaffolds project structure and configuration.",
204
+ "author": "Anthropic",
205
+ "category": "devtools",
206
+ "tags": ["agent-sdk", "scaffold", "setup"],
207
+ "roles": ["backend", "fullstack"],
208
+ "source": "claude-official",
209
+ "icon": "N"
210
+ },
211
+ {
212
+ "id": "explanatory-output",
213
+ "name": "Explanatory Output",
214
+ "description": "Output style that explains reasoning and decisions. Teaches while building — great for learning and code review.",
215
+ "author": "Anthropic",
216
+ "category": "workflow",
217
+ "tags": ["output-style", "learning", "explanatory"],
218
+ "roles": [],
219
+ "source": "claude-official",
220
+ "icon": "E"
221
+ },
222
+ {
223
+ "id": "learning-output",
224
+ "name": "Learning Output",
225
+ "description": "Output style optimized for learning. Step-by-step explanations, concept breakdowns, guided understanding.",
226
+ "author": "Anthropic",
227
+ "category": "workflow",
228
+ "tags": ["output-style", "learning", "educational"],
229
+ "roles": [],
230
+ "source": "claude-official",
231
+ "icon": "W"
232
+ }
233
+ ]
@@ -365,6 +365,47 @@ export function createApi(app, daemon) {
365
365
  res.json(daemon.adaptive.getAllProfiles());
366
366
  });
367
367
 
368
+ // --- Skills Marketplace ---
369
+
370
+ app.get('/api/skills/registry', (req, res) => {
371
+ const skills = daemon.skills.getRegistry({
372
+ search: req.query.search || '',
373
+ category: req.query.category || 'all',
374
+ });
375
+ res.json({
376
+ skills,
377
+ categories: daemon.skills.getCategories(),
378
+ });
379
+ });
380
+
381
+ app.get('/api/skills/installed', (req, res) => {
382
+ res.json(daemon.skills.getInstalled());
383
+ });
384
+
385
+ app.post('/api/skills/:id/install', (req, res) => {
386
+ try {
387
+ const result = daemon.skills.install(req.params.id);
388
+ res.json(result);
389
+ } catch (err) {
390
+ res.status(400).json({ error: err.message });
391
+ }
392
+ });
393
+
394
+ app.delete('/api/skills/:id', (req, res) => {
395
+ try {
396
+ const result = daemon.skills.uninstall(req.params.id);
397
+ res.json(result);
398
+ } catch (err) {
399
+ res.status(400).json({ error: err.message });
400
+ }
401
+ });
402
+
403
+ app.get('/api/skills/:id/content', (req, res) => {
404
+ const content = daemon.skills.getContent(req.params.id);
405
+ if (!content) return res.status(404).json({ error: 'Skill not installed' });
406
+ res.json({ id: req.params.id, content });
407
+ });
408
+
368
409
  // --- Directory Browser ---
369
410
 
370
411
  app.get('/api/browse', (req, res) => {
@@ -27,6 +27,7 @@ import { ProjectManager } from './pm.js';
27
27
  import { CodebaseIndexer } from './indexer.js';
28
28
  import { AuditLogger } from './audit.js';
29
29
  import { Federation } from './federation.js';
30
+ import { SkillStore } from './skills.js';
30
31
  import { isFirstRun, runFirstTimeSetup, loadConfig, saveConfig, printWelcome } from './firstrun.js';
31
32
 
32
33
  const DEFAULT_PORT = 31415;
@@ -115,6 +116,7 @@ export class Daemon {
115
116
  this.indexer = new CodebaseIndexer(this);
116
117
  this.audit = new AuditLogger(this.grooveDir);
117
118
  this.federation = new Federation(this);
119
+ this.skills = new SkillStore(this);
118
120
 
119
121
  // HTTP + WebSocket server
120
122
  this.app = express();
@@ -0,0 +1,198 @@
1
+ // GROOVE — Skill Store
2
+ // FSL-1.1-Apache-2.0 — see LICENSE
3
+
4
+ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, unlinkSync, rmSync } from 'fs';
5
+ import { resolve, dirname } from 'path';
6
+ import { fileURLToPath } from 'url';
7
+
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+
10
+ export class SkillStore {
11
+ constructor(daemon) {
12
+ this.daemon = daemon;
13
+ this.skillsDir = resolve(daemon.grooveDir, 'skills');
14
+ mkdirSync(this.skillsDir, { recursive: true });
15
+
16
+ // Load bundled registry
17
+ this.registry = [];
18
+ try {
19
+ const regPath = resolve(__dirname, '../skills-registry.json');
20
+ this.registry = JSON.parse(readFileSync(regPath, 'utf8'));
21
+ } catch { /* no registry file */ }
22
+ }
23
+
24
+ /**
25
+ * Get all skills from the registry with installed status.
26
+ */
27
+ getRegistry(query) {
28
+ let skills = this.registry.map((s) => ({
29
+ ...s,
30
+ installed: this._isInstalled(s.id),
31
+ }));
32
+
33
+ // Search filter
34
+ if (query?.search) {
35
+ const q = query.search.toLowerCase();
36
+ skills = skills.filter((s) =>
37
+ s.name.toLowerCase().includes(q)
38
+ || s.description.toLowerCase().includes(q)
39
+ || s.tags.some((t) => t.includes(q))
40
+ );
41
+ }
42
+
43
+ // Category filter
44
+ if (query?.category && query.category !== 'all') {
45
+ skills = skills.filter((s) => s.category === query.category);
46
+ }
47
+
48
+ return skills;
49
+ }
50
+
51
+ /**
52
+ * Get installed skills only.
53
+ */
54
+ getInstalled() {
55
+ const installed = [];
56
+ if (!existsSync(this.skillsDir)) return installed;
57
+
58
+ for (const dir of readdirSync(this.skillsDir, { withFileTypes: true })) {
59
+ if (!dir.isDirectory()) continue;
60
+ const skillPath = resolve(this.skillsDir, dir.name, 'SKILL.md');
61
+ if (!existsSync(skillPath)) continue;
62
+
63
+ const content = readFileSync(skillPath, 'utf8');
64
+ const meta = this._parseFrontmatter(content);
65
+
66
+ // Merge with registry info if available
67
+ const regEntry = this.registry.find((r) => r.id === dir.name);
68
+
69
+ installed.push({
70
+ id: dir.name,
71
+ name: meta.name || regEntry?.name || dir.name,
72
+ description: meta.description || regEntry?.description || '',
73
+ category: regEntry?.category || 'custom',
74
+ tags: regEntry?.tags || [],
75
+ roles: regEntry?.roles || [],
76
+ author: regEntry?.author || 'local',
77
+ installed: true,
78
+ });
79
+ }
80
+
81
+ return installed;
82
+ }
83
+
84
+ /**
85
+ * Install a skill from the registry.
86
+ * Copies the SKILL.md content from the Claude plugins directory.
87
+ */
88
+ install(skillId) {
89
+ const entry = this.registry.find((s) => s.id === skillId);
90
+ if (!entry) throw new Error(`Skill not found: ${skillId}`);
91
+ if (this._isInstalled(skillId)) throw new Error(`Skill already installed: ${skillId}`);
92
+
93
+ // Find the skill content from Claude's plugin directory
94
+ const content = this._findSkillContent(skillId);
95
+ if (!content) {
96
+ throw new Error(`Skill content not found. Make sure Claude Code plugins are installed.`);
97
+ }
98
+
99
+ // Save to .groove/skills/<id>/SKILL.md
100
+ const skillDir = resolve(this.skillsDir, skillId);
101
+ mkdirSync(skillDir, { recursive: true });
102
+ writeFileSync(resolve(skillDir, 'SKILL.md'), content);
103
+
104
+ this.daemon.audit.log('skill.install', { id: skillId, name: entry.name });
105
+
106
+ return { id: skillId, name: entry.name, installed: true };
107
+ }
108
+
109
+ /**
110
+ * Uninstall a skill.
111
+ */
112
+ uninstall(skillId) {
113
+ const skillDir = resolve(this.skillsDir, skillId);
114
+ if (!existsSync(skillDir)) throw new Error(`Skill not installed: ${skillId}`);
115
+
116
+ rmSync(skillDir, { recursive: true });
117
+ this.daemon.audit.log('skill.uninstall', { id: skillId });
118
+
119
+ return { id: skillId, installed: false };
120
+ }
121
+
122
+ /**
123
+ * Get the full content of an installed skill.
124
+ */
125
+ getContent(skillId) {
126
+ const skillPath = resolve(this.skillsDir, skillId, 'SKILL.md');
127
+ if (!existsSync(skillPath)) return null;
128
+ return readFileSync(skillPath, 'utf8');
129
+ }
130
+
131
+ /**
132
+ * Get available categories from the registry.
133
+ */
134
+ getCategories() {
135
+ const cats = new Map();
136
+ for (const skill of this.registry) {
137
+ const count = cats.get(skill.category) || 0;
138
+ cats.set(skill.category, count + 1);
139
+ }
140
+ return Array.from(cats.entries())
141
+ .map(([id, count]) => ({ id, count }))
142
+ .sort((a, b) => b.count - a.count);
143
+ }
144
+
145
+ // --- Internal ---
146
+
147
+ _isInstalled(skillId) {
148
+ return existsSync(resolve(this.skillsDir, skillId, 'SKILL.md'));
149
+ }
150
+
151
+ _findSkillContent(skillId) {
152
+ // Search Claude's plugins directory for the skill
153
+ const pluginsBase = resolve(process.env.HOME || '~', '.claude', 'plugins', 'marketplaces', 'claude-plugins-official', 'plugins');
154
+
155
+ if (!existsSync(pluginsBase)) return null;
156
+
157
+ // Skills can be nested: plugins/<plugin>/skills/<skill>/SKILL.md
158
+ for (const pluginDir of readdirSync(pluginsBase)) {
159
+ const skillsPath = resolve(pluginsBase, pluginDir, 'skills');
160
+ if (!existsSync(skillsPath)) continue;
161
+
162
+ for (const skillDir of readdirSync(skillsPath)) {
163
+ if (skillDir === skillId || pluginDir === skillId) {
164
+ const skillFile = resolve(skillsPath, skillDir, 'SKILL.md');
165
+ if (existsSync(skillFile)) {
166
+ return readFileSync(skillFile, 'utf8');
167
+ }
168
+ }
169
+ }
170
+
171
+ // Also check commands/<id>.md
172
+ const cmdsPath = resolve(pluginsBase, pluginDir, 'commands');
173
+ if (!existsSync(cmdsPath)) continue;
174
+
175
+ const cmdFile = resolve(cmdsPath, `${skillId}.md`);
176
+ if (existsSync(cmdFile)) {
177
+ return readFileSync(cmdFile, 'utf8');
178
+ }
179
+ }
180
+
181
+ return null;
182
+ }
183
+
184
+ _parseFrontmatter(content) {
185
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
186
+ if (!match) return {};
187
+
188
+ const meta = {};
189
+ for (const line of match[1].split('\n')) {
190
+ const sep = line.indexOf(':');
191
+ if (sep === -1) continue;
192
+ const key = line.slice(0, sep).trim();
193
+ const val = line.slice(sep + 1).trim();
194
+ meta[key] = val;
195
+ }
196
+ return meta;
197
+ }
198
+ }